2017-09-27 94 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。