Testing web services using in-memory web containers
This post was published on January 29, 2015Last week, I read an interesting blog post on how to test Java web services inside an in-memory web container. I thought it was a fast and elegant solution to overcome a well-known unit testing problem: unit tests for web services become cumbersome when your web services uses the services provided by the container and you need to mock these container services. On the other hand, if you don’t mock these, your unit tests are virtually worthless. The blog post, originally written by Antonio Goncalves, provides an elegant solution to this problem: use an in-memory container. In this case, he uses Sun’s implementation of Java SE 6, which includes a light-weight HTTP server API and implementation: com.sun.net.httpserver.
In this post, I will show a slightly improved version of his solution using my own web service implementation. In order to get the example below to work, all I needed to do was include a recent version of the javax.jws library, which you can find for example here.
I have constructed a simple service that, given a composer, returns his name, his best known work, his country of birth and his age of death. The interface for this service looks like this:
import javax.jws.WebService; @WebService public interface LookUp { public String getName(Composer composer); public String getMostPopularComposition(Composer composer); public String getCountryOfBirth (Composer composer); public Integer getAge (Composer composer); }
The implementation of this web service is a simple class calling the get methods of the Composer class:
import javax.jws.WebService; @WebService(endpointInterface = "com.ontestautomation.webservice.LookUp") public class ComposerLookUp implements LookUp { @Override public String getName(Composer composer) { return composer.getName(); } @Override public String getMostPopularComposition(Composer composer) { return composer.getMostPopularComposition(); } @Override public String getCountryOfBirth(Composer composer) { return composer.getCountryOfBirth(); } @Override public Integer getAge(Composer composer) { return composer.getAge(); } }
The Composer class itself contains nothing more get and set methods for the Composer properties (the code below shows an example for only one property, the others are very similar):
public class Composer { String name; String mostPopularComposition; String countryOfBirth; Integer age; public Composer() { } public Composer(String name, String composition, String country, int age) { this.name = name; this.mostPopularComposition = composition; this.countryOfBirth = country; this.age = age; } public void setMostPopularComposition(String composition) { this.mostPopularComposition = composition; } public String getMostPopularComposition() { return this.mostPopularComposition; } }
And now for the interesting part. We have defined a (very simple) web service, but how are we going to test it?
As said, using only a couple of lines of code, we can simply deploy our service in an in-memory container and call the methods from our test. First, let’s see how we can deploy and start the web service:
public class ComposerLookUpIntegrationTest { LookUp composerLookUp; Endpoint endpoint; @BeforeSuite public void setupService() throws MalformedURLException { // Publish the SOAP Web Service on a given endpoint endpoint = Endpoint.publish("http://localhost:8080/composerLookUp", new ComposerLookUp()); // Provide data to access the web service URL wsdlDocumentLocation = new URL("http://localhost:8080/composerLookUp?wsdl"); String namespaceURI = "http://webservice.ontestautomation.com/"; String servicePart = "ComposerLookUpService"; String portName = "ComposerLookUpPort"; QName serviceQN = new QName(namespaceURI, servicePart); QName portQN = new QName(namespaceURI, portName); // Create a service instance Service service = Service.create(wsdlDocumentLocation, serviceQN); composerLookUp = service.getPort(portQN, LookUp.class); }
The publish() method in the Endpoint class uses by default the light-weight HTTP server implementation that is included in Sun’s Java SE distribution. The only downside is that this HTTP server is in a com.sun package and therefore might not be portable.
To verify that we have indeed successfully launched our web service, let’s open the URL to the WSDL in a browser:
That was easy, right? Now we can define whichever test we want to perform on our web service. Again, I used TestNG as a test framework:
@Test public void checkComposerAge() { // Create a new Composer object Composer composer = new Composer("Mozart","Requiem","Austria",35); // Check whether the service returns the right data Assert.assertEquals(composerLookUp.getAge(composer),new Integer(35),"Mozart died at the age of 35"); }
Notice that we call the method as defined in the web service interface LookUp rather than the get method of the Composer class, as that would defy the purpose of our test altogether!
Next to the functional test, we can also easily perform a test that checks whether our web service has been deployed successfully:
@Test public void checkServiceIsSetupProperly() { // Check that the service is published Assert.assertTrue(endpoint.isPublished()); // Check that the service has the correct binding Assert.assertEquals("http://schemas.xmlsoap.org/wsdl/soap/http", endpoint.getBinding().getBindingID(),"Verify that the service binding is correct"); }
When I run the test suite containing this test (and two other tests), we can see that our tests are all executed successfully:
Hopefully this post has shown you how you can easily deploy and test a web service within an actual web container, without having to do a lot of cumbersome coding and/or configuration.
An Eclipse project containing the complete code for the sample web service and the tests that I have written and executed can be downloaded from here.
"