Monday, May 12, 2014

MockServer: Easy mocking of HTTP(S) services (e.g. SOAP or JSON)

Testing services as an atomic entity can be difficult. Especially if these services are part of a call chain or call other services. Often in such cases mock services are developed to reduce test dependencies and exclude services which are not interesting to the specific test case. For example, I'm testing service A. Service A calls service B. I'm not interested in service B (or service B is maintained by another department on which I don't want to depend). I would mock service B when testing service A in this case. There are several methods to create mock services. These methods however are mostly not easily usable by testers since they require developing/coding mock services. Testers would benefit from being able to create their own mock services in order to create different tests for a specific service.

In this blog post I provide a brief introduction and describe some features of MockServer. An open source product which can be used to mock services. For a more detailed article (with more examples) you can look at the following written by my colleague Robert van Mölken: http://technology.amis.nl/2014/03/06/functional-boundary-testing-of-a-service-based-environment-using-mockserver/

The below image was taken from http://www.mock-server.com/

Coding mocks

Mocks can be developed and coded. The described methods are not suitable for testers (without programming background).

Mock services for developers

There are two flavors of mocks. Mocks from within the code and 'mocks' providing a minimal implementation of the actual service.

Mocks from within the code
Mock code can be part of the test code and provide for example a service response without actually having called the service. See for a nice although slightly old comparison of several frameworks; http://softwareinabottle.wordpress.com/2010/09/12/finding-the-mock-framework-that-best-suits-me-part-1-the-contenders/. These mocking frameworks can be further classified in ones that use proxy objects and ones that use a mechanism called class remapping (see for an explanation of the concepts: http://java.dzone.com/articles/the-concept-mocking). Mockito and Powermock are examples of frameworks which do class remapping. See http://javaoraclesoa.blogspot.nl/2013/10/java-unit-testing-mocking-jndi-final.html for some examples on how to mock private and static methods by using Mockito and Powermock. Reflection (http://docs.oracle.com/javase/tutorial/reflect/) can also be used as mocking aid in addition to the frameworks. These mocks don't pass the transport/network layer since they work from within the code.

Limited implementations
Limited implementations can be used to mock services. There are frameworks available which allow generation of skeleton services from service definitions. This service can then be further developed and deployed to provide a mock implementation. These implementations however are often specific to one type of service, for example SOAP services (JAX-WS wsimport utility, see here). In certain cases it is not straightforward to generate a skeleton service such as with REST services. There does not appear to be a consensus in the community on whether to use a definition for REST services such as WADL. Also JSON lacks a widely implemented schema definition standard. Without a strict definition of the URL handling (REST) or the message format (JSON), skeleton code cannot be generated or is not very usable. In such cases, creating a mock might require more coding. Limited implementations require deployment. The network/transport layer can also be taken into account, possibly providing some extra information on connectivity and network performance.

MockServer

Recently I stumbled upon MockServer (http://www.mock-server.com/). My first impression was that this would yet be another Java specific mocking framework which would require programming in order to build services. I appeared to be wrong however.

MockServer provides HTTP/HTTPS mock services based on expectations of requests and responses linked to the request. A MockServer 'service implementation' consists of configuration of a running MockServer instance. This configuration can be provided by a client. Java/JavaScript clients are provided but a REST interface is also available.

MockServer can be downloaded as a standalone JAR including dependencies which can be run from the command line, or can be deployed on an application server of choice (similar to for example Hudson/Jenkins).

The below images illustrate how MockServer can be used. The images were taken from http://www.mock-server.com/.

The below image illustrates a production environment. A system is dependent on three services. These services might be absent in the test environment and/or out of scope for test.


A test system can use mock services to provide endpoints for required services and responses. This allows a reduction in scope and dependencies of tests to be executed.



Setting expectations with SOAP UI

Expectations are messages which have similar properties such as call an URL ending with /myservice. Regular expressions can be used to specify expectations. Together with the expectation, the user provides a response. MockServer has clients for JavaScript and Java. The Java client can for example be used to program out expectations. MockServer however can also be fed 'raw' JSON to load expectations from any other tool such as SOAP-UI. This allows creating mock services without deployments or coding. Also it doesn't matter if we're mocking SOAP services, REST/JSON services or even complete JSF pages as long as we feed it enough expectations and responses. A tester can use this for example in combination with SOAP-UI.

In the below screenshot an expectation is loaded from SOAP UI into MockServer;


If I send a post request to /login on the MockServer, it returns JSON "{ message: 'incorrect username and password combination' }".


Other requests return a default HTTP 404 error.

TIP: if you're having difficulties with generating the right expectation you can program it out in Java using the Java client (when not using Maven, take the MockServer JAR which already contains the dependencies) and then use JDeveloper HTTP analyzer (http://docs.oracle.com/cd/E24382_01/user.1112/e17455/aud_prof_test_apps.htm) to capture the request for MockServer and use that request.

TIP: by default, if an expectation is met, the response is returned. If the same request is offered again, a 404 is returned. To change this behavior, use an example expectation like;

 {  
  "httpRequest" : {  
   "method" : "POST",  
   "path" : "/login"  
  },  
  "httpResponse" : {  
   "statusCode" : 200,  
   "body" : "{ message: 'incorrect username and password combination' }",  
   "headers" : [ {  
    "name" : "Content-Type",  
    "values" : [ "application/json; charset=utf-8" ]  
   }, {  
    "name" : "Cache-Control",  
    "values" : [ "public, max-age=86400" ]  
   } ],  
   "times" : {"unlimited": true}  
  }  
 }  

TIP: In order to create an initial set of expectations and simplify initial setup, MockServer can be run as a transparent proxy recording requests and responses. Of course the clients of the services which will be mocked, need to be configured to use MockServer as proxy for this to work. The requests/responses can be saved in a log file. Since the requests contain client specific headers and session id's, some refinement will probably be needed to make the expectations more reusable. After refinement, they can be fed to MockServer as expectations. It is also possible to directly generate Java MockServer client code from the recorded requests/responses.

Using variables with SOAP UI

MockServer does not natively allow the use of variables in expectations. You can not use part of the request directly in the response. You can of course use the client to provide that functionality. However when you use the Java or JavaScript provided libraries, it will require some coding. You can also provide similar functionality from a client like SOAP UI with relatively little scripting (more tester friendly).


In this example (SOAP UI project can be downloaded here) I've used a property defined on the testcase. I've used this property in the expectation request to MockServer and in the assertion for the response (login, not visible in the screenshot). If you define the REST resources for MockServer in SOAP UI, a WADL can be generated. This WADL (or the SOAP UI project \as a whole) can be reused. The supplied SOAP UI project can be used as a start for this.

Considerations

Although MockServer provides useful functionality to implement mock services, there are several things to consider. Below I'm also providing some pointers which might help if you consider using MockServer.

MockServer allows mocking HTTP and HTTPS requests, thus (among others) SOAP services and REST/JSON services. It's functionality is relatively basic so you need something around it to provide required expectations. This can be done from for example SOAP UI.

MockServer runs in memory. Upon restart of MockServer, all expectations are lost. This requires loading them externally from a MockServer client (Java/JavaScript code or for example SOAP UI) in order for expectations to be reused. Since MockServer runs in memory, it is not practical to provide an extremely large numbers of expectations in order to for example mock entire applications; keep it small and simple.

If a single MockServer instance is used to mock services for multiple services (maybe maintained/developed by different teams), it is useful to start a SOAP UI testsuite with first clearing up specifically the expectations which are relevant for the test to be performed. It is also a good idea to clear up the expectations you've set after having performed the test to not influence other tests.

MockServer is setup at a specific host/port. You need to replace endpoints in calls for clients so the MockServer is called instead of the actual service. If MockServer is used as a proxy to record requests/responses, the clients of the services need to be configured to use MockServer as a proxy.

When you want to mock Oracle SOA web-services, often abstract WSDL's are used (see here). The webservice binding is determined at runtime. This requires MockServer to provide a WSDL which contains the concrete binding at runtime and not only the endpoint.

MockServer expectations are executed in the order in which they are setup. You can use this to for example define a 'catchall' SOAP fault when testing a specific service so the response message always conforms to the WSDL.

MockServer has several methods which allow writing specific information to log files. These log files however cannot be returned directly by using the REST API. To analyse them you need to have access to the specific log files on the file-system where MockServer is running.

Configuration of MockServer is done at the commandline. If this configuration needs to be changed, MockServer needs to be restarted. When MockServer is run on an applicationserver, direct access to the machine running MockServer is not required for a restart; this can usually be done from the application server console.

MockServer provides a Maven Plugin and can be used as part of a Continuous Delivery process to automate specific tests.

No comments:

Post a Comment