1

I'm new to unit test and Mockito. I got confused by what I should test and verify. I have a class A as follows:

public class A{ @Autowired private B b; public double doSomething(Request r){ r = b.process1(r); r = b.process2(r); return calculateFinal(r); } public void reportSomething(Request r){ r = b.process1(r); r = b.process2(r); b.report(r); } private int calculateFinal(Request r){ return r.getFinalScore() * 2; } } 

Suppose I want to test these two methods with Junit test. Since I have a dependency B in A, I mock it with Mockito. For both tests, I was told that I should assume that the dependency b is fully tested and properly working since we want to test the business logic in A.

At first it looks like that I don't have to test anything for reportSomething() since it only involves calls to b and they are all "working"? The only thing I can think of to test is whether they are actually called and the order of the calls, correct? So should I just call a.reportSomething() and then do the verification? One thing that bugs me is that whether I should stub the b.process1() and b.process2() to return anything. I tried without stubbing anything and it worked, but why?

For testDoSomething(), I think what I'm really testing is the calculateFinal() method. But since it uses the data from the Request object, I need to set that data in Request r first. Since r directly comes from b.process2(), I should stub the method call to return a Request object with that data. But I could skip the stubbing of b.process1(), right?

Is this a right thinking process? Did I miss something or misunderstand something? If it's right, is there a better and cleaner way to write it? Thank you!

public class ATest{ private static final int SCORE = 100; @Mock private B mockB; @InjectMocks private A aClient; @Before public void setUpTest{ MockitoAnnotations.initMocks(this); } @Test public void testReportSomething(){ // what should I test here? Request r = new Request(); // is it necessary to include the following two lines? when(mockB.process1(any(Request.class))).return(r); when(mockB.process2(any(Request.class))).return(r); aClient.reportSomething(r); InOrder inOrder = inOrder(mockProcesser); inOrder.verify(mockProcesser).process1(any(Request.class)); inOrder.verify(mockProcesser).process2(any(Request.class)); inOrder.verify(mockProcesser).report(any(Request.class)); } @Test public void testDoSomething(){ // Is this correct? Request r = new Request(); r.setFinal(SCORE); // I skipped this line and it still works when(mockB.process1(any(Request.class))).return(r); when(mockB.process2(any(Request.class))).return(r); assert(SCORE * 2, aClient.doSomething(r)); // is it still necessary to verify the call to mockB? } } 

1 Answer 1

2

You are doing your test incorrectly. Let's look at the method you want to test:

public void reportSomething(Request r){ r = b.process1(r); r = b.process2(r); b.report(r); } 

First of all, you need to mock that when b processes a request, it returns the expected result; DO NOT therefore use the same return value for two invocations.

Here is how I would write the test:

final Request r = mock(Request.class); final Request r1 = mock(Request.class); final Request r2 = mock(Request.class); when(mockB.process1(r)).thenReturn(r1); when(mockB.process2(r1)).thenReturn(r2); doNothing().when(mockB).report(any(Request.class)); final InOrder inOrder = inOrder(mockB); // Launch... And then verify: inOrder.verify(mockB).process1(r); inOrder.verify(mockB).process2(r1); inOrder.verify(mockB).report(r2); inOrder.verifyNoMoreInteractions(); 

As to:

 // is it necessary to include the following two lines? 

Yes. By default, when unspecified, a mocked instance will return Java's defaults: 0 for numeric primitives, false for boolean, null for objects. You MUST specify what you want to be returned by stubbing.

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

3 Comments

So even though that we know the dependency b works properly, we still need to mock it by "when b processes a request, it returns the expected result"? Also, why doNothing().when(mockB).report(any(Request.class)); but not doNothing().when(mockB).report(r2);? Thanks.
b may work properly but here you don't test b; as do the second point, it is to broaden the scope of the stub. It is verifications which matter, and you want to test that b.report() was called with r2.
On a side note, I would add that testing once the code is done is usually a lot trickier as the code is a lot less test friendly. If mocks are needed this becomes even more delicate without refactoring.