2

Consider a class that uses an external jar. The class processes objects of type D, which are obtained via objects A, B, and C, all of which external objects from the jar.

class DProcessor() { public void process(PoolOfA pool) { A a = pool.borrowObject() ... B b = a.getB() C c = b.getC() for (D d : c.getAllDs()) { // Do something meaningful with d } } } 

How do I Unit test process(PoolOfA pool)?

My best shot so far is writing mocks for all external classes:

PoolOfA pool = mock(PoolOfA.class); A a = mock(A.class); B b = mock(B.class); C c = mock(C.class); D d1 = mock(D.class); D d2 = mock(D.class); D d3 = mock(D.class); D d4 = mock(D.class); List listOfDs = new ArrayList<D>(); listOfDs.add(d1); listOfDs.add(d2); listOfDs.add(d3); listOfDs.add(d4); // Set specific behaviour for each d when(pool.borrowObject()).thenReturn(a); when(b.getC()).thenReturn(a); when(c.getAllDs()).thenReturn(d); when(b.getC()).thenReturn(c); when(c.getAllDs()).thenReturn(listOfDs); 

This seems cumbersome and inelegant. Is there a better way?

3 Answers 3

4

Better way is to rewrite the method, of course. But if you cannot do it for some reason, mockito offers great feature called 'deep stubs'. Check out the docs.

Sign up to request clarification or add additional context in comments.

2 Comments

I like the doc: "every time a mock returns a mock a fairy dies." ;-)
@assylias and the documentation says that for a reason. Deep stubs should generally be avoided whereever possible. Refactoring the code as suggested by assylias and Vitality is the much preferable solution. The "legacy-api" argument doesn't catch in this case since you're obviously in full control.
2

What process really does, is process some Ds in the loop. I would first make it clear by changing the signature:

public void process(Collection<D> allDs) 

Now you can test that more easily by mocking D only.

That method can either be public if it can replace the existing one or package private for example if you don't want to expose it. In that latter case, you might still want to test that the other process method (the one that takes a poolOfA) properly extract the Ds. But that means that process(PoolOfA) needs to know a lot about the poolOfA which does not seem right.

This is one of the ideas promoted by this "Guide to writing testable code" which I think contains interesting concepts. What you mention would probably fall into the "Digging into Collaborators" section.

Comments

1

I would suggest a small redesign of the process method: It is currently responsible for doing two things: Extracting an Iterable of D's from the internals of the input and processing them.

So actually, you method, although declaring that it is expecting an input of type PoolOfA, is absolutely not interested in this object. It wants what's inside. I wold declare the method as taking an Iterable and pass the responsibility to the caller to give it the correct input. This will clarify the intention of the method and make it easier to test.

You may say: "this is not a real solution, this is just moving the problem to another location! now I need to test the calling method!"

Well, yes and no. First, remember that you do not have to UT everything, just for the sake of coverage. You should focus your UT efforts on algorithmic pieces of code, it is OK to skip trivial object interactions.

If you insist, you can use more powerful mocking libraries like PowerMock in order to mock only past of your class, but this is a discussion for a different Question.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.