簡體   English   中英

Mockito 驗證單元測試 - 需要但未調用。 實際上,與此模擬的交互為零

[英]Mockito verify unit test - Wanted but not invoked. Actually, there were zero interactions with this mock

起初我想為我的英語感到抱歉。

我開始進行一些單元測試(我以前從未做過,我是編程新手)。

我必須使用 mockito.verify 測試簡單的將產品添加到數據庫(DynamoDB)方法,但我有

"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(
    model.kitchen.Product@a0136253
);
-> at     service.kitchen.KitchenServiceTest.addProduct(KitchenServiceTest.java:80)
Actually, there were zero interactions with this mock.

有人能告訴我我做錯了什么嗎?

您應該模擬和驗證的是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對象調用就足夠了。

Mocking 是一種工具,您僅將其用於正在測試的類的依賴項。 您的測試似乎並不關心 Author、Media 和 Product 對象,這些只是您要測試的方法的依賴項; 嘲笑他們。

組織將極大地幫助您的測試; 做這樣的事情:

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

唯一應該嘲笑的東西——如果有的話——是ObjectMapper 和databaseController。 一個只模擬合作者對象,幾乎從不模擬被測系統/類(在 SUT 上“窺探”的情況非常罕見)。 並且取決於 ObjectMapper 是什么以及它的操作有多透明,您可能真的不想模擬它。 此外,由於您的實現代碼是通過直接調用構造函數來實例化 ObjectMapper 編寫的,因此您甚至無法模擬它。

雖然我喜歡 Mockito 和模擬對象的使用,但有時使用盡可能多的真實對象進行簡單測試是值得的。 當您的協作者簡單、直接、沒有副作用並且不需要復雜的初始化或設置時,尤其如此。 僅在簡化測試設置或驗證時使用模擬。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM