Showing posts with label mock. Show all posts
Showing posts with label mock. Show all posts

Mock, Mock... who's that? (Part 2)

Starting off where I left my first introductory post of this series - so I chose Mockito as my mocker. What next?

The Requirements For Mocking
Following are the requirements that we wanted to fill up (for starters). Though these requirements are specific to mine, I'm sure almost every project would have the same / similar mocking requirements :
  1. Objective : The most important point of using mocking frameworks was to emulate certain behaviour from instances of external dependencies.
    • Lets continue with this example :

      +--------------------------------------------------+
      |    MyLoginService --uses-->  BackendAuthService  |
      |                                    |             |
      |                             authenticates via    |
      |                                    |             |
      |                                    v             |
      |                                DataSource        |
      +--------------------------------------------------+
    • Here the objective is to unit test MyLoginService's login API, which in its integration environment would talk to multiple backend services.
    • Lets assume that the BackendAuthService has an API named login, which accepts a custom class object. This custom class object contains the details of the credentials to authenticate.
    • Further, lets say this API returns another custom class object which is the authenticated token after successful authentication. Also, if the authentication fails when this API throws an exception.
  2. Independence : While unit testing (in my Dev or on the continuous integration farm), I cannot expect the backend services to be available / functional. Hence, unit testers will choose to mock-out the behaviour expected from these external dependencies.
    • Note that this implies that the developer first needs to know possible behaviours exhibited by these dependencies (SuccessCase1, SuccessCase2, FailCase1, FailCase2, ExceptionCase1, ....).
    • Then s/he should code the unit test case, such that when the external dependencies are called / invoked, they exhibit the behaviour the unit test case is supposed to test.
    • Generally, there would be at least one unit test case for each expected scenario. In addition there would be negative test cases as well. 
    • A point to explain what I mean by  "mock-out the behaviour". In the above example, for a positive test case, we need (to simulate) the backend service returning a valid authenticated token, signifying successful authentication. Using the mocking framework, we can induce this simulation on the backend service instance.
  3. Integration : Moving on, the production code uses implementation classes injected via a Spring(-like) framework. So there are configuration files where mappings are defined, injection customizations and finally, instance look up code.
    • Modifying the production code flow, for adding any unit testing capability is forbidden.
    • Hence, we want to re-use the injection framework, configuration files and the same instance look up code, to seamlessly work while unit testing.
  4. Thread Safety : We wanted to be able to run unit tests in parallel. This is very easily possible via TestNG, in addition to the load of unit test features it provides. In a typical production environment, all instances of these external dependencies are expected to be thread safe. Obviously, we want that behaviour to remain even in the mocks.
  5. Distinct behaviour per thread : In spite of requirement (4), since every thread in the unit test case would be a test for a different scenario, a developer would want each mock for each test case to behave differently. So though we want thread safety, we also want the mocks to behave differently in each thread.
Cool! So we now know what we want to do. Moving on to how it was done.

Approaches Possible
Before I explicitly state the solution we adopted, I want to discuss the various possibilities we considered. This section talks about those.
  1. Spring supports two bean scopes by default for standalone applications - prototype and singleton (default). What we needed was a way to define mock implementation classes in the spring configuration, such that each thread would have its own mocked instance - basically thread scope. This way the thread safety of the mocked instance and different-behaviour-per-thread requirements can be achieved.
    • One way out here was to define a custom scope in Spring. (see also the SimpleThreadScope class in available in 3.0.x version).
    • Another way out is to ask Spring to use factories for bean creation and then take control over this aspect by implementing a factory.
  2. We wanted the capability to choose / change mocker implementations in the future. Hence, we wanted control over the way these mock objects were created / initialized / refreshed etc... - so we wanted to implement the factory that Spring would turn to for bean instance creation.
    • Spring provides a convenient way to do this - using FactoryBeans. By implementing FactoryBean interface, we can write a factory class that will generate beans as well as control singleton behaviour.
    • Other methods using instance factories and static factories are also possible
Approach Implemented
  1. Use an implementation of Spring's FactoryBean to serve as a factory for creating beans. This implementation, lets name it MockServiceLookUp, will be called whenever the code flow requests for some bean.
  2. The MockServiceLookUp implementation is responsible for creating mocked instances for the class that is being looked up - one instance per thread.
  3. The MockServiceLookUp implementation will rely on the use of a MockProvider to create actual mock objects. The MockProvider is the class that will actually use the mocker library to create mocks.
    • Ideally, MockProvider should be an interface, with multiple implementations for each type of mocker you want to support (so that those can be plugged in as needed). 
    • Alternately, MockProvider can be skipped completely and the mocker library can be used in the look up implementation to create mock instances.
  4. For every look up request, the MockServiceLookUp will first check whether a mock implementation for the class being looked up exists in its ThreadLocal. If it does, the instance is returned, otherwise the MockProvider is consulted.
    • The general case is that unit test will fetch the mock instance for a class that the actual code the unit test is for will be using. Then the unit test would "apply" behaviour mocking on this instance (i.e. behavior stubbing) and finally call the actual API to test.
    • Since the API would also look up the same class from Spring (which in turn will request MockServiceLookUp for the instance), the API would get a mock instance with appropriate methods stubbed. These methods would be those that the unit test expects the API to call on the backend/dependency. Hence, the unit test would be complete.
  5. Finally, the MockServiceLookUp also provided for a "clear all" API to erase all the stubbing performed on the mock instances in its ThreadLocal.
    • This was a useful API for us - to start afresh from within a unit test - where we wanted to discard all previous stubbing
    • This API was also called by default from out unit testing infrastructure whenever a new unit test case started - hence ensuring all unit tests started clean.
Conclusion
This is what the mock framework class diagram (taken with permission - thanks to my colleague Siju) is like :



Finally, a unit test would run like this :
    • Unit Test Case Start
    • Use Spring to fetch the implementation for BackendAuthService.
      • Spring would invoke the MockServiceLookUp's getObject() API to get the implementation of BackendAuthService.
      • MockServiceLookUp would first check if an existing implementation of the class exists already, in its ThreadLocal. If this is the first getObject call for this class, then the mock method of the MockProvider is called. Otherwise, the mock instance from ThreadLocal is returned.
      • The MockProvider will use Mockito to create the mock instance of the specified class.
    • The unit test will override the behaviour of the BackendAuthService's login API
      • The behaviour override can be to return valid values (auth tokens) or invalid values (excetpions, errors, invalid auth tokens) depending on what is being tested
    • Then the test would make a call to MyLoginService's login API
      • This implementation would again request Spring for the implementation of the BackendAuthService class, which this time will be the stubbed mock instance.
      • When the login API on BackendAuthService is called the stubbed code executes returning the auth token / exception.
    • After the API call completes, the unit test must verify that the auth token returned is valid or not (or if an exception was excepted, whether it was thrown or not).
    • Unit Test Case End
Hope this post has helped you understand how "instances" of classes are mocked and injected into production code, in a distinct-behaviour-per-thread manner. Good luck with mocking!

Mock, Mock... who's that? (Part 1)

Let me begin with this quote from Martin Fowler's post :
The term 'Mock Objects' has become a popular one to describe special case objects that mimic real objects for testing. Most language environments now have frameworks that make it easy to create mock objects. What's often not realized, however, is that mock objects are but one form of special case test object, one that enables a different style of testing.
Mocking - huh?
This post series is not to explain / debate on mocking and stubbing test strategies. If you are interested in reading what mocks are, why to use them and so on, please refer to the following links :
If you have decided to take the mock path and are interested in how to use mocks, please read on. Here is my agenda on covering what I've learned from my project's mock testing efforts :
  1. Mocking libraries and comparison. What I've finally used and why
  2. Mocking of instance functions, in a thread safe manner
  3. Mocking of static functions, in a thread safe manner
  4. Mocking of static getInstance() / factory methods, in a thread safe manner
Though my mock usage examples would be in Java, most of the concepts can be used across languages. So, here we go...

Mocking libraries and comparison
There are multiple library projects that offer mocking and stubbing functionality. The number of choices are overwhelming and its often difficult to decide what's the right one to choose. For starters, simple dynamic proxy or sub-classing "mockers" would be just fine. For advances usages, "mockers" with greater benefits - probably state maintenance, static mocking would be useful.

A comparison of currently available mock libraries can be found here :
  1. JMockit documentation recently hosted an exhaustive comparison matrix recently.
  2. A comparison by Vasily Sizov on his blog from March 2009.
  3. StackOverFlow.com users had this great discussion over mock library choices

Our initial set of candidates included EasyMock and Mockito. Though JMockit sounded very tempting, due to lack of documentation (about 4 months back - though its improved quite a lot now) we did not want to adopt it - or so we thought.

EasyMock and Mockito are both very easy to code to and it was a tough call which one to use. Finally, multiple team members got their hands dirty using the two libraries and we voted. The winner was Mockito - we simply loved its documentation (everything was just there) and the extensibility for mocking behaviors. I have been happily mocking using Mockito since then - here I have use and like about Mockit :
  • unlike EasyMock, Mockito is not a "record-n-play" mocker. You mock out what is necessary, when it is necessary, make unit test API calls and then verify expectations - all on demand.
  • behavior mocking is very simple, written like English sentences in code : when(BasicService.foo()).thenReturn(retval);
  • throwing exceptions, tracking number of calls made was possible and easy
  • the return values from mock methods can be customized using the API call parameters.
  • verification of mocked behavior is easy. Though there is no auto-verification feature.
Hope this post will help you find your mocker. I will follow up with more posts on how we used mocks in a thread safe manner, injected them into Spring and how mocking static functions made us use a mix of Mockito and JMockit :). Stay tuned!
     
    Stats