2014-12-28 220 views
1

我是新困惑。我对我应该测试和验证的内容感到困惑。我有一个类如下:通过单元测试和单元的Mockito和测试的Mockito

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; 
    } 
} 

假设我想用Junit测试来测试这两种方法。由于我在A中有一个依赖关系B,所以我用Mockito来嘲笑它。对于这两种测试中,有人告诉我,我应该承担的依赖b的全面测试和正常工作,因为我们要测试的业务逻辑A.

起初它看起来像我没有测试任何东西对于reportSomething(),因为它只涉及拨打b,他们都“工作”?我能想到的唯一要测试的是他们是否真的被调用,调用的顺序是否正确?所以我应该只需调用a.reportSomething()然后进行验证?有一点让我感到困惑的是,我是否应该存根b.process1()和b.process2()来返回任何东西。我尝试了没有琢磨任何东西,它的工作原理,但为什么?

对于testDoSomething(),我想我真正的测试是calculateFinal()方法。但是由于它使用来自Request对象的数据,所以我需要首先在请求r中设置这些数据。由于r直接来自b.process2(),我应该存根方法调用以返回具有该数据的Request对象。但我可以跳过b.process1()的残局,对吧?

这是一个正确的思维过程?我错过了什么或误解了什么?如果它是正确的,是否有更好更清洁的方式来编写它?谢谢!

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? 
    } 
} 

回答

2

您正在错误地做你的测试。让我们来看看该方法要测试:

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

首先,你需要模拟是当B处理的请求时,它返回预期结果;因此不要在两次调用中使用相同的返回值。

这是我会怎么写测试:

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(); 

至于:

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

是。默认情况下,未指定时,模拟实例将返回Java的默认值:数字基元为0,布尔值为false,对象为null。你必须指定你想要通过存根返回的东西。

+0

因此,即使我们知道了依赖B工作正常,我们仍然需要通过“b时处理一个请求时,它会返回预期的结果”嘲笑呢?另外,为什么'doNothing()。when(mockB).report(any(Request.class));'but not'doNothing()。when(mockB).report(r2);'?谢谢。 – SteelwingsJZ

+0

'b'可以正常工作,但在这里你不测试'B';就像第二点一样,它是扩大存根的范围。验证是重要的,并且你想要测试'b.report()'是否被'r2'调用。 – fge

+2

在附注中,我会在代码完成后添加该测试通常会非常棘手,因为代码对测试友好性要差得多。如果需要嘲笑,这将变得更加微妙而不重构。 – Brice

相关问题