43

How does one mock the many dependencies needed for integration tests?

I use Mockito for my 'pure' unit tests. 'Pure' in this case means testing a single class, mocking all of it's dependencies. Beautiful.

Now come integration tests. Let's say in this case an integration test will test something like this:

  1. Message is put on a queue
  2. Message is 'processed'
  3. Response message is put on a response queue

Let's also say that the processing that happens in step 2 is serious stuff. It relies on lots of database interactions, on multiple external services, the file system, all kinds of things. There are also a lot of side effects that the flow will trigger, so I cannot simply ensure that the response is correct - I need to verify the side effects.

Each of these dependencies are wrapped by a single stateless service class, which makes them nice and mockable.

How are folks handling this?

I would love to use Mockito so that I could verify the side effects that the above flow will have. However, Mocktio's documentation (and to a large extent it's implementation) seems to fight strongly against using it in contexts other than 'pure' unit tests. I've tried to go this route, but

  • It's difficult to populate the stub data (as there's lots of it)
  • It's difficult to have Spring inject those stubbed instances into my beans
  • It's difficult to 'reset' the mocks so that I can verify a different set of interactions without clearing out the stubs.

EDIT

I know that I could handle the database issue with something like an HSQLDB instance, but there's still the issue of the external services. For repeatability I can't rely on those services being up, being in the state that I require, etc. The only option I see there is to mock them.

Whatdaya do?

Roy Truelove
  • 22,016
  • 18
  • 111
  • 153
  • 1
    Just to clarify, as integration testing can be taken in two ways. It sounds like you mean integration testing as in, testing that connecting components work well together (essentially testing the API's). But, sometimes integration refers to end-to-end, so you would not mock your service and actually allow it to hit the database. This clarification can help with the answer..Please see http://stackoverflow.com/questions/4904096/whats-the-difference-between-unit-functional-acceptance-and-integration-test for further clarification of the types – Justin Pihony Apr 12 '12 at 21:06
  • It really applies to any test (integration or end-to-end) that requires a lot of external dependencies. For instance I could replace my database stubs with an HSQLDB instance, but I still have all of the other services. Will edit the question a bit to clarify.. – Roy Truelove Apr 13 '12 at 01:06
  • So how did you resolve the mocking issue eventually? – Pupsik May 19 '15 at 14:34

3 Answers3

14

Great question.

It seems like you hit the limits of Mockito. Mockito is great if what you want to inspect object interactions.

What you want, though, seems to be observability (and controllability) at a higher level of abstraction. I'm afraid that the mocks or stubs you need for that should be carefully designed and hand-crafted.

At the unit level, these mocks can be nicely generated, by means of Mockito. At the integration level, this becomes much harder, and you will need purpose made testability interfaces.

avandeursen
  • 8,458
  • 3
  • 41
  • 51
  • 1
    Yeah it sounds like at the integration level folks 'make the best of it', either by doing what they can with mocking libraries or by actually hitting test instances of services / database. I'm currently working on a Groovy based Mockito extension to help the integration testing be a bit less painful. – Roy Truelove Apr 16 '12 at 01:07
8

In order to mock things like databases, web services, the file system and so on, you will probably want to refactor a little. For each external service, you should write a wrapper class that has a method for each operation that you wish to perform. Each such method should have no actual logic, but just pass through its parameters in the way that the external service will understand, and return an object that contains whatever data the external service returns. For example, if you're interacting with a database, the wrapper class might format its parameters into an SQL statement, submit them into an existing Connection object, and return a List for the result.

Because the methods of the wrapper class contain no logic (that is, no if/else, no loops and no exception handling); there is no need to unit test the wrapper class. You should integration test the wrapper class, to make sure that its responsibilities are performed correctly (that is, that the SQL statement has the desired effect on the database, for example).

Now re-write the classes that interact with the external services so that they interact with the wrapper classes instead. It's then easy to unit test them - you just have to mock the wrapper classes.

Dawood ibn Kareem
  • 77,785
  • 15
  • 98
  • 110
  • 1
    Thanks David. My external services are pretty well abstracted out- each is wrapped with a single Spring singleton service class. Even with this, for a complicated scenario, mocking becomes difficult. There is a lot of data that needs to be stubbed, often the same service method will be called many times which means I need to have the stubs return multiple values, then there's the issue of getting those injected with Spring.. gets hairy. I have to assume that folks have solved this in a cleaner way – Roy Truelove Apr 13 '12 at 12:31
  • Do they have to be wrapped with a singleton? Singletons are notoriously hard to mock. Can you engineer things so that the wrapper is not a singleton? – Dawood ibn Kareem Apr 13 '12 at 12:38
  • Also, I would query why the same service method is being called many times within one test. Perhaps your test methods are too big? I am a firm believer in the "one assert per test method" rule; it really does make for much cleaner tests. – Dawood ibn Kareem Apr 13 '12 at 12:43
  • Re: singletons - they are injected by spring, not the old 'static getInstance()' type. This actually makes them very easy to test. See this: http://stackoverflow.com/a/2302246/295797. Also, the point of the post was exactly to handle large tests. I have my suite of small 'one assert per test method' tests, but the reality is that integration tests in complicated systems are going to call the same service method multiple times. – Roy Truelove Apr 13 '12 at 12:59
  • Sorry, you did mention that it was a big integration test. So ignore my comment about one assert per test. My experience is that Mockito lends itself quite nicely to big integration tests though. I assume you know how to get Mockito to do different things on successive calls to the same mock method? I'm sorry that I wasn't able to be more help. – Dawood ibn Kareem Apr 13 '12 at 13:07
-2

If there is some http or rest mock framework, using that should be good.

All the complicated dependencies can be recorded, modified and replayed.

Hangfei Lin
  • 107
  • 3
  • 4