Spring Integration Tests, Part II, Using Mock Objects

In the previous post, I wrote how you can use Spring’s FactoryBean to facilitate the creation of mock objects for Spring integration tests. Now, it is time to use the EasyMockFactoryBean (in this post EasyMock has been used for creating mock objects, but a similar approach applies to Mockito as well. Start by looking at the MockitoFactoryBean).

Next, imagine that the Facade class and the Delegate interface below are part of a bigger system:


Create a matching easymock-test-config.xml (or mockito-test-config.xml).

Now, we have all the bits and pieces that are needed to start writing the integration test. We start simple to make sure that we autowiring and Spring context has been configured correctly:

The test is executed and it passes without any problem.

A second test is added to the same file with some added mock behavior:

Excellent, that test also passes.

Now that we have warmed up, we add a third test to the test class:

As expected, this test also passes without any problem.

Unfortunately, that is not always true. A closer investigation reveals that all tests pass when they are executed individually. When executing all three tests (either from the IDE or from a build tool like Maven), the third test fails unexpectedly:

This is EasyMock telling us that the mock object is in the wrong state. An EasyMock mock object goes through a series of steps:

  1. Initialization – Instantiate the mock object.
  2. Record – Record the expectations of the mock object.
  3. Replay – Call replay() on the mock object so that it can replay the recorded state.
  4. Test – Execute the test assertions.
  5. Verify – Call verify() on the mock object to certify that the recorded mock expectations are fulfilled.

In an ordinary unit test, the mock object is thrown away after the verify phase, a new mock instance is created before the next test that can be used to record the new behavior. However, since we are creating a Spring integration test, there is one more thing to consider.

Reused beans

In the testing chapter of the Spring manual it is stated that:

By default, once loaded, the configured ApplicationContext and all of its beans are reused for each test method. Thus the setup cost is incurred only once (per test fixture), and subsequent test execution is much faster.

Consequently, all Spring beans, including mocked beans, will preserve their state between different test methods. The mock object will be in the verify state when the last test begins and not in the record state when delegateMock.doSomethingElse() is called. To solve the problem, we need some mechanism to ensure that the mock object is in a known, well-defined state before each test.

Reset mocks

Both EasyMock and Mockito provide methods to reset() the state of the mocked objects. Normally, resetting mock objects in the middle of a test method is considered to be a potential code smell, because it is likely that you are testing too much and that the test could be refactored into two separate tests accordingly. Nonetheless, resetting the mock instance @Before each test allow us to keep the same mock instance through the entire lifetime of the test class and yet put it in the record state when before each test starts:

When executing all tests in the test class, we see that that the problem has been solved and all tests pass.
For reference, click the link for the full source code of the EasyMock test class (and the Mockito test class).

Comments

You may choose to reset the mocks @After each test, the result will be the same.

The reset() method is called between the different test methods (because of the nature of @After and @Before), so the code smell of calling reset within a test is avoided.

Tests written using Mockito mocks are generally more tolerant for this kind of problem. In contrast to EasyMock, Mockito has no replay() method and no notion of steps. Therefore, it is possible to add additional mock expectations and to replace existing expectations, both after the test has been executed as well as after the result has been verified. Hence, you should always reset your mock objects before each test so that you do not get any accidental mocking behavior.

As a side note, another solution would be to annotate the test class (or all of its test methods) with the @DirtiesContext annotation. This will effectively recreate the entire application context after each test has been executed, causing all Spring beans to be in their initial state and thus the mock beans to be in the record state. Although this will work, there will be a significant performance penalty compared to the suggested reset() and @Before / @After solution, because all beans in the application context will be recreated and re-wired before each test method.

Dependencies

  • Spring 3.0.6
  • Mockito 1.8.5
  • jUnit 4.10
  • EasyMock 3.1

References

Previous post: Spring Integration Tests, Part I, Creating Mock Objects

Mattias Severson

Mattias is a senior software engineer specialized in backend architecture and development with experience of cloud based applications and scalable solutions. He is a clean code proponent who appreciates Agile methodologies and pragmatic Test Driven Development. Mattias has experience from many different environments, including everything between big international projects that last for years and solo, single day jobs. He is open-minded and curious about new technologies. Mattias believes in continuous improvement on a personal level as well as in the projects that he is working on. Additionally, Mattias is a frequent speaker at user groups, companies and conferences.

This Post Has 5 Comments

  1. Hi Mattias,

    thanks for sharing this stuff, I’m glad to see that I’m not the only one doing it (done it twice with a dependency that couldn’t be set up for tests easily). I’ve noticed strange reactions when people see such solution ;) but I think it’s a good trick to have in your toolbox.

    However, there’s one thing in your post that I feel should be clarified:

    “since Mockito discourage verification of mock objects”

    I think this is not precise enough. Mockito discourages verification of stubs (indirect inputs for the system-under-test), but not mocks (indirect outputs of SUT). I think it’s quite important to make that distinction as people tend to mix the two kinds of test doubles and write some superfluous code like verification of stubs. As Mockito’s author Szczepan Faber wrote in his blog (http://monkeyisland.pl/2008/04/26/asking-and-telling/) stubbing is part of the setup and verifying recorded behaviour is asserting on the test results. I’m glad there’s a mockito framework that gets the difference :)

  2. @Marcin: Thanks for your feedback, I updated the comment about Mockito.

    1. @Sergey: Thanks for the reference. Another approach is to create a separate Java-based test configuration that is responsible for providing the mock objects. When included by the @ContextConfiguration in a test, it is obvious that we are dealing with mocked beans.

Leave a Reply

Close Menu