Java : How to implement stateful webservice calls by REST? - web-services

I'm implementing a web service by RESTFul API.
How to make the same instance available to many webservice calls, and keep in memory the new status of this instance?
Let's consider we have an object Obj1 (having as attributes Id and Rank) and many webservice calls : call1 for method increment(), call2 for method getRankeValue()...
Let's suppose that (Obj1.Rank==0) was equal to true, and let's suppose that call1 has done Obj1.Rank++.
How can we make call2 say that (Obj1.Rank==1) was equal to true?
Thank you a lot.

Create a method that generates a unique token and use in all other method calls, so the server can keep track of state.

Related

Accessing request container (event_dispatcher) within a test client

I created a simple test case in Symfony.
So one client which should listen for an event which will be dispatched during an request.
But nothing happen because the request have an own scope or I dont know why Im not able to access the dispatcher in it.
$this->client = static::createClient();
self::$container = $this->client->getContainer();
$dispatcher = self::$container->get('event_dispatcher');
$dispatcher->addListener('example', function ($event) {
// Never executed
});
$this->client->request('POST', $endpoint, $this->getNextRequestParameters($i), [$file], $this->requestHeaders);
$this->client->getResponse();
The listener is never called.
When I debug it a bit I find out that the object hash via spl_object_hash($dispatcher) is different on the highest level than on within the request level.
So it seems that the request has an own world and ignores everything outside.
But then is the question how I can put my listener to this "world"?
I think part of the problem is the mixing of testing styles. You have a WebTestCase which is intended for a very high level of testing (requests & responses). It should not really care about internals, i.e. which services or listeners are called. It only cares that given input x (your request) you will get output y (your response). This allows to ensure the basic functionality as perceived by your users is always met, without caring how it is done. Making these tests very flexible.
By looking into the container and the services you are going into a lower level of testing, which tests interconnected services. This is usually only done within the same process for the reasons you already found out. The higher level test has 2 separate lifecycles, one for the test itself and one for the simulated web request to your application, hence the different object ids.
The solution is either to emit something to the higher level, e.g. by setting headers or changing the output, so you can inspect the response body. You could also write into some log file and check the logs before/after the request for that message.
A different option would be to move the whole test into a lower level where you do not need the requests and instead only work with the services. For this you can use the KernelTestCase (instead of the WebTestCase) and instead of calling createClient() you call bootKernel. This will give you access to your container where you can modify the EventDispatcher. Rather than sending a request you can then either call the code directly, e.g. dispatch an event if you only want to test the listeners, or you can make your controller accessible as service and then manually create a request, call the action and then either check the response or whatever else you want to assert on. This could look roughly like this:
public function testActionFiresEvent()
{
$kernel = static::bootKernel();
$eventDispatcher = $kernel->getContainer()->get('event_dispatcher');
// ...
$request = Request::create();
// This might not work when the controller
// You can create a service configuration only used by tests,
// e.g. "config/services_test.yaml" and provide the controller service there
$controller = $kernel->getContainer()->get(MyController::class);
$response = $controller->endpointAction($request);
// ...Do assertions...
}

Symfony2: Mocked service is set in the container but not used by the controller (it still uses the original service)

I'm writing the functional tests for a controller.
It uses a class to import some data from third party websites and to do this I wrote a class that I use into Symfony setting it a service.
Now, in my functional tests, I want to substitute this service with a mocked one, set it in the container and use it in my functional tests.
So my code is the following:
// Mock the ImportDataManager and substitute it in the services container
$mockDataImportManager = $this->getMockBuilder('\AppBundle\Manager\DataImportManager')->disableOriginalConstructor()->getMock();
$client->getContainer()->set('shq.manager.DataImport', $mockDataImportManager);
$client->submit($form);
$crawler = $client->followRedirect();
As I know that between each request the client reboots the kernel and I have to set again the mocked class, I set the mock immediately before the calling to $client->submit.
But this approach seems not working for me and the controller still continue to use the real version of the service instead of the mocked one.
How can I use the mocked class to avoid to call the remote website during my functional test?
If I dump the set mocked service, I can see it is correctly set:
dump($client->getContainer()->get('shq.manager.DataImport'));die;
returns
.SetUpControllerTest.php on line 145:
Mock_DataImportManager_d2bab1e7 {#4807
-__phpunit_invocationMocker: null
-__phpunit_originalObject: null
-em: null
-remotes: null
-tokenGenerator: null
-passwordEncoder: null
-userManager: null
}
But it is not used during the $form->submit($form) call and, instead, is used the original service.
UPDATE
Continuing searching for a solution, I landed on this GitHub page from the Symfony project, where a user asks for a solution to my same problem.
The second call doesn't use the mocked/substituted version of his class, but, instead, the original one.
Is this the correct behavior? So, is it true that I cannot modify the service container on a second call to the client?
Yet, I don't understand why the service is not substituted in the container and I haven't a real solution to that problem.
Anyway I found some sort of workaround, in reality more correct as solution (also if it remains unclear why the service is not substituted and this is a curiosity I'd like to solve - maybe because the $client->submit() method uses the POST method?).
My workaround is a simple test double.
I create a new class in AppBundle/Tests/TestDouble and called it DataImportManagerTestDouble.php.
It contains the unique method used by the controller:
namespace AppBundle\Tests\TestDouble;
use AppBundle\Entity\User;
class DataImportManagerTestDouble
{
public function importData(User $user)
{
return true;
}
}
Then, I instantiate it in the config_test.yml (app/config/config_test.yml) file in the following way:
services:
shq.manager.DataImport:
class: AppBundle\Tests\TestDouble\DataImportManagerTestDouble
This way, during the tests, and only during the tests, the class loaded as service is the TestDouble and not the original one.
So the test pass and I'm (relatively) happy. For the moment, at least.

Unit test for web service (Service Reference) - xml deserialization

In Summary
I need a way to deserialize an XML string into an object normally returned by a 3rd party webservice.
Using C#.
In Detail
I have code that consumes a 3rd party Service Reference (Web Service) - so the usual stuff: we pass in a Request object and it returns a Response object.
Regarding unit testing - I'm not interested in the inner workings of the Service Reference since this is a 3rd party service. I'm only interested in two things:
Does my code generate the correct Request object?
When the Service Reference returns it's response, do I process this response correctly?
Taking each in turn:
Does my code generate the correct Request object?
This I can do. If anyone's interested in this, what I do is to replace my service reference with a RhinoMocks Mock object. In my unit test I call the method on my Mock and then check the arguments passed in, comparing the actual Request object against the expected Request object.
When the Service Reference returns it's response, do I process this response correctly?
What I want to do here is to create a RhinoMocks Stub of my service reference, so that when it's called this stub returns a response object populated with my test data.
The problem that I face is that the response objects returned by this particular 3rd party service are extremely complex. If I were to attempt to create one by hard-coding all the property values by hand then this would probably take me the best part of a whole day.
However, what I can very easily do is to capture the XML serialized response from this service. I could then easily edit it's values and store this XML in one of my unit tests.
What I'm after is an easy way to then "deserialize" this "test" XML into a response object and use this to program the response from my Stub.
Any help would be much appreciated.
Thanks
Griff
Turns out that this is quite simple:
public static object Deserialize(string xml, Type toType)
{
using(Stream stream = new MemoryStream())
{
byte[] data = System.Text.Encoding.UTF8.GetBytes(xml);
stream.Write(data, 0, data.Length);
stream.Position = 0;
var s = new XmlSerializer(toType, "http://^your url^");
return s.Deserialize(stream);
}
}
Note that if you're using XML from a SOAP request, strip the SOAP envelop off first.
Griff

Factory pattern for test and live web services

Can web services be used in a factory pattern given that the code is auto-generated and I do not want to alter it (to add a base class for example)?
A reason to do this would be if you had 2 web services that were identical but one was for test data and one was for live data and you wanted to switch between the services based on the environment the code was runnig in.
[Edit]
I am using C# 3.
If you're using C# and SOAP, you can change the destination at runtime:
var webSvc = new WebServerObjectName();
webSvc.Url = "http://examples/com/foo.asmx";
//or pull from .config, etc.
webSvc.Url = ConfigurationManager.AppSettings["WebServiceUri"].ToString();
//make the call to the web method
var custs = webSvc.GetCustomerList();
The flow would be:
at design-time, make the web reference. Establish the contract, and code for it (input & output params). You'll only need to make it once, as long as the contract stays the same.
at run-time, change the URL/URI/target of the web service. Obviously it would have to have the same contract/params/method signature, otherwise the call would fail at runtime.
make the call

Strategies to mock a webservice

I'm implementing a client consuming a webservice. I want to reduce dependencies and decided to mock the webservice.
I use mockito, it has the advantage vs. EasyMock to be able to mock classes, not just interfaces. But that's not the point.
In my test, I've got this code:
// Mock the required objects
Document mDocument = mock(Document.class);
Element mRootElement = mock(Element.class);
Element mGeonameElement = mock(Element.class);
Element mLatElement = mock(Element.class);
Element mLonElement = mock(Element.class);
// record their behavior
when(mDocument.getRootElement()).thenReturn(mRootElement);
when(mRootElement.getChild("geoname")).thenReturn(mGeonameElement);
when(mGeonameElement.getChild("lat")).thenReturn(mLatElement);
when(mGeonameElement.getChild("lon")).thenReturn(mLonElement);
// A_LOCATION_BEAN is a simple pojo for lat & lon, don't care about it!
when(mLatElement.getText()).thenReturn(
Float.toString(A_LOCATION_BEAN.getLat()));
when(mLonElement.getText()).thenReturn(
Float.toString(A_LOCATION_BEAN.getLon()));
// let it work!
GeoLocationFetcher geoLocationFetcher = GeoLocationFetcher
.getInstance();
LocationBean locationBean = geoLocationFetcher
.extractGeoLocationFromXml(mDocument);
// verify their behavior
verify(mDocument).getRootElement();
verify(mRootElement).getChild("geoname");
verify(mGeonameElement).getChild("lat");
verify(mGeonameElement).getChild("lon");
verify(mLatElement).getText();
verify(mLonElement).getText();
assertEquals(A_LOCATION_BEAN, locationBean);
What my code shows is that I "micro-test" the consuming object. It's like I would implement my productive code in my test. An example for the result xml is London on GeoNames.
In my opinion, it's far too granular.
But how can I mock a webservice without giving everystep? Should I let the mock object just return a XML file?
It's not about the code, but the approach.
I'm using JUnit 4.x and Mockito 1.7
I think the real problem here is that you have a singleton that calls and creates the web service so it is difficult to insert a mock one.
You may have to add (possibly package level) access to the singleton class. For example if the constructor looks something like
private GeoLocationFactory(WebService service) {
...
}
you can make the constructor package level and just create one with a mocked web service.
Alternatively you can set the webservice by adding a setter method, although I don't like mutable Singletons. Also in that case you have to remember to unset the webservice afterwards.
If the webservice is created in a method you might have to make the GeoLocationFactory extensible to substitute the mock service.
You may also look into remove the singleton itself. There are articles online and probably here on how to do that.
you really want to be mocking the results returned from the webservice to the code that will be using the result. In your example code above you seem to be mocking mDocument but you really want to pass in an instance of mDocument that has been returned from a mocked instance of your webservice and assert that the locationBean returned from the geoLocationFetcher matches the value of A_LOCATION_BEAN.
The easiest option would be to mock the WebService client,
when(geoLocationFetcher.extractGeoLocationFromXml(anyString()))
.thenReturn("<location/>");
You can modify the code to read the response xml from the file system.
Sample code can be found here: Mocking .NET WebServices with Mockito