2017-09-27 58 views
1

起初我想抱歉我的英文。Mockito验证单元测试 - 通缉但未调用。其实,这个模拟与零交互

我开始做一些单元测试(我从来没有这样做过,我是编程中的新人)。

考试我一定要简单增加产品数据库(DynamoDB)方法使用mockito.verify但我有

"Wanted but not invoked. Actually, there were zero interactions with this mock." 

错误,我不知道该怎么办。

这是我的方法的代码(在KitchenService类):

public Product addProduct(Product content) { 

    ObjectMapper objectMapper = new ObjectMapper(); 

    String mediaJSON = null; 
    String authorJSON = null; 
    String productKindsJSON = null; 
    try { 
     mediaJSON = objectMapper.writeValueAsString(content.getMedia()); 
     authorJSON = objectMapper.writeValueAsString(content.getAuthor()); 
     productKindsJSON = objectMapper.writeValueAsString(content.getProductKinds()); 
    } catch (JsonProcessingException e) { 
     logger.log(e.getMessage()); 
    } 


    Item item = new Item() 
      .withPrimaryKey("id", UUID.randomUUID().toString()) 
      .with("name", content.getName()) 
      .with("calories", content.getCalories()) 
      .with("fat", content.getFat()) 
      .with("carbo", content.getCarbo()) 
      .with("protein", content.getProtein()) 
      .with("productKinds", productKindsJSON) 
      .with("author", authorJSON) 
      .with("media", mediaJSON) 
      .with("approved", content.getApproved()); 


    Item save = databaseController.saveProduct(PRODUCT_TABLE, item); 
    logger.log(save + " created"); 



    return content; 

} 

这是测试代码:

@Test 
public void addProduct() throws Exception { 


    KitchenService instance = mock(KitchenService.class); 


    Product expectedProduct = new Product(); 
    expectedProduct.setName("kaszanka"); 
    expectedProduct.setCalories(1000); 
    expectedProduct.setFat(40.00); 
    expectedProduct.setCarbo(20.00); 
    expectedProduct.setProtein(40.00); 
    expectedProduct.setProductKinds(Collections.singletonList(ProductKind.MEAT)); 
    expectedProduct.setApproved(false); 
    Author expectedAuthor = new Author(); 
    expectedAuthor.setId("testID"); 
    expectedAuthor.setName("Endrju Golota"); 
    expectedProduct.setAuthor(expectedAuthor); 
    Media expectedMedia = new Media(); 
    expectedMedia.setMediaType(MediaType.IMAGE); 
    expectedMedia.setName("dupajasia"); 
    expectedMedia.setUrl("http://blabla.pl"); 
    expectedProduct.setMedia(expectedMedia); 

    verify(instance, times(1)).addProduct(expectedProduct); 
} 

这是我测试后得到:

Wanted but not invoked: 
kitchenService.addProduct(
    [email protected] 
); 
-> at  service.kitchen.KitchenServiceTest.addProduct(KitchenServiceTest.java:80) 
Actually, there were zero interactions with this mock. 

有人能告诉我什么我做错了吗?

+1

你不应该嘲笑被测试的班级。如果有什么可以嘲笑的话,那就是ObjectMapper –

+0

那么如何使用验证并调用没有kitchenservice实例的方法? 正确验证的示例: verify(mock).someMethod(); (模拟,时间(10))。someMethod();验证(模拟,atLeastOnce())。someMethod(); –

+0

你的测试没有意义。你在嘲笑你正在测试的东西。所以你没有执行你的任何代码。只有Mockito的代码。创建一个假的东西,调用假的东西方法,并确认你已经调用了假的东西方法是没有意义的。真正的代码永远不会被执行,你所做的只是使用假的东西。当你想测试A时,嘲笑是有用的,而A取决于B,而你使用假B来测试A.阅读https://stackoverflow.com/a/28783849/571407获取详细解释。 –

回答

0

你应该嘲笑和验证是databaseController依赖性:

@Test 
public void addProduct() throws Exception { 

    KitchenService instance = new KitchenService(); // you should create the class under test 

    DatabaseController controllerMock = mock(DatabaseController.class); // mock the controller 

    instance.setController(controller); // inject the mock 

    ... 

    // Act 
    instance.addProduct(expectedProduct); 

    // Assert 
    verify(controller).saveProduct(Mockito.eq(PRODUCT_TABLE), Mockito.any(Item.class)); 

} 

您应该验证数据库服务中调用..检查它与任何Item对象调用应该是足够了。

0

模拟是一种工具,您只能用于正在测试的类的依赖关系。 看来您的测试不关心作者,媒体和产品对象,这些只是您要测试的方法的依赖关系; 嘲笑他们。

组织将极大地帮助您的测试; 做这样的事情:

public class TestKitchenService 
{ 
    private static String VALUE_PRODUCT_NAME = "VALUE_PRODUCT_NAME"; 
    ... use constants for other values as well. The value of the constant does not matter. 

    @InjectMocks 
    private KitchenService classToTest; 

    private InOrder inOrder; 

    @Mock 
    private Author mockAuthor; 

    @Mock 
    private DatabaseController mockDatabaseController; 

    @Mock 
    private Logger mockLogger; 

    @Mock 
    private Media mockMedia; 

    @Mock 
    private Product mockProduct; 

    @After 
    public void afterTest() 
    { 
     inOrder.verifyNoMoreInteractions(); 

     verifyNoMoreInteractions(mockAuthor); 
     verifyNoMoreInteractions(mockDatabaseController); 
     verifyNoMoreInteractions(mockLogger); 
     verifyNoMoreInteractions(mockMedia); 
     verifyNoMoreInteractions(mockProduct); 
    } 

    @Before 
    public void beforeTest() 
    { 
     MockitoAnnotations.initMocks(this); 

     doReturn(mockAuthor).when(mockProduct).getAuthor(); 
     doReturn(mockMedia).when(mockProduct).getMedia(); 
     doReturn(VALUE_PRODUCT_NAME).when(mockProduct).getName(); 
     doReturn(Collections.singletonList(ProductKind.MEAT)).when(mockProduct).getProductKinds(); 

     ... doReturns for the other product values. 

     inOrder = inOrder(
      mockAuthor, 
      mockDatabaseController, 
      mockLogger, 
      mockMedia, 
      mockProduct); 

     ReflectionTestUtils.setField(
      classToTest, 
      "databaseController", 
      mockDatabaseController); 

     ReflectionTestUtils.setField(
      classToTest, 
      "logger", 
      mockLogger); 
    } 

    @Test 
    public void addProduct_success() 
    { 
     final Product actualResult; 


     actualResult = classToTest.addProduct(mockProduct); 


     assertEquals(
      mockProduct, 
      actualResult); 

     inOrder.verify(mockProduct).getMedia(); 

     inOrder.verify(mockProduct).getAuthor(); 

     inOrder.verify(mockProduct).getProductKinds(); 

     inOrder.verify(mockProduct).getName(); 

     ... inOrder.verify for the other product values. 

     inOrder.verify(mockDatabaseController).saveProduct(
      eq(PRODUCT_TABLE), 
      any(Item.class)); 
    } 
} 
0

应该被嘲笑的唯一的东西 - 如果有的话 - 是ObjectMapper和databaseController。一个只会模仿协作者对象,而且几乎不会是被测试的系统/类(在SUT上“侦察”的情况非常罕见)。取决于ObjectMapper是什么以及它的操作是多么透明,你甚至不想嘲笑它。此外,由于您的实现代码是通过直接调用构造函数来实例化ObjectMapper的,因此您甚至不能嘲笑它。

虽然我喜欢使用Mockito和模拟对象,但有时仅用尽可能多的真实对象进行测试是值得的。当您的协作者简单,直接,没有副作用并且不需要复杂的初始化或设置时,情况尤其如此。只有在简化测试设置或验证时才使用mock。