Test Driven Web Service Client Development
Join the DZone community and get the full member experience.
Join For FreeThis article is about test driven development of web service clients. Since we will be talking about unit tests, functional tests, test driven development and other test related topic, I'd like to clarify the terminology first.
Let's start with unit tests. A unit test is an automated test that tests only one small part of our application in isolation. A unit test should not interact with file system, database or a third party library. Why? Mainly because we want to test only the code and nothing else. We also want to execute the test as fast as possible without any configuration hassle.
Sometimes we need to test more then just a code. Sometimes it's necessary to test configuration or interaction with an ORM library. Sometimes we want to test some layer of the application that is not easily testable. We have to keep in mind, that in usual enterprise application the code is just one part of the whole system. We usually have some XML configuration files, annotations, JSP pages and so on. This parts have to be tested too.
And that's what functional tests are for. A functional test is an automated test that tests more parts of the application together. There is whole spectrum of functional tests. On one side it can be a simple test which looks like an unit test but it tests several classes in one go. On the other side it can be a big complicated test that tests together all layers of the application – from JSPs to database. Obviously, functional tests are slower, they do not tell us where the bug is and they are more prone to configuration errors.
Test Driven Development a technique that can be used when developing new functionality. First a failing test is written, then new functionality that makes the test pass is added. What kind of tests should be used for test driven development (TDD)? Unit or functional tests? Usually unit tests are used. It makes sense. TDD should drive us to write better code and unit tests are code related. But there are occasions, where it makes sense to use functional tests for TDD. One example is data access layer, but today I want to write about WS clients so I will focus on them.
Classical WS client access layer looks like this (pseudo-code)
ReturnValue wsClientMethod(inputData)
{
request = convertInputDataToRequest(inputData);
response = callService(request);
return convertResponseToReturnValue(response);
}
First of all we have to convert input data to a request. Here we can either generate XML directly or we can use an Object/XML mapping tool. Then we have to call the service and convert the response back to some values that are expected as return value.
Now let's imagine how the unit test would look like. The tests of convert methods would be really boring. The converter method itself is usually an ugly bunch of set methods. You know, stuff like “get the name from this bean and set it to that bean, take the address from the first bean and set it to the other, ...”. The test would be quite similar in it's ugliness. I am able to write such code once but no-one will force me to write it twice.
Let's think how to do it better. If you are using Spring WS, you can use Spring WS Test library to make your life easier.
We can start with the following test.
@Test
public void testGetFligts()
{
//create control
WsMockControl mockControl = new WsMockControl();
//teach mock what to do and create it
WebServiceMessageSender mockMessageSender = mockControl.expectRequest("PRG-DUB-request.xml").createMock();
webServiceTemplate.setMessageSender(mockMessageSender);
client.getFlights("PRG","DUB");
mockControl.verify();
}
Here we test get flights method. First of all a mock is created. The mock expects, that the service will be called with request specified in a XML file. If the service is not called or the request differs, the test fails. Please note that we do not have to implement the boring comparison of the request. It's done automatically based on the XML file. The test is not only simpler, it's also more useful. It also tests that correct XML is generated. I admit, it's not an unit test. It tests third partly library (XML mapping) and it accesses the file system. But it's pretty fast and there is not much configuration needed. It combines speed of unit tests with usefulness of functional tests.
To make the previous test pass, we have to implement the request transformation and WS call. But that's not all, we have to simulate the server response and check its transformation. It's quite easy.
@Test
public void testGetFligts()
{
//create control
WsMockControl mockControl = new WsMockControl();
//teach mock what to do and create it
WebServiceMessageSender mockMessageSender = mockControl.expectRequest("PRG-DUB-request.xml")
.returnResponse("PRG-DUB-response.xml").createMock();
webServiceTemplate.setMessageSender(mockMessageSender);
//do the test
List<Flight> flights = client.getFlights("PRG","DUB");
assertNotNull(flights);
assertEquals(1, flights.size());
assertEquals("PRG",flights.get(0).getFrom().getCode());
assertEquals("DUB",flights.get(0).getTo().getCode());
//verify that everything was called at least once
mockControl.verify();
}
The only difference is, that we had to add response to the mock and compare the result with expectations. The mock response is again specified as an XML file, so it's quite intuitive to do it. Full code is accessible here.
Writing test in this way is quite easy and fast. It's also more obvious what the test is trying to achieve. You can focus on the functionality, you can think about possible request/response combinations. If you want to give it a try, you can download the tool here.
Opinions expressed by DZone contributors are their own.
Trending
-
Observability Architecture: Financial Payments Introduction
-
The SPACE Framework for Developer Productivity
-
Operator Overloading in Java
-
Implementing a Serverless DevOps Pipeline With AWS Lambda and CodePipeline
Comments