Mockito 验证单元测试 - 需要但未调用。事实上,与这个模拟的互动为零

问题描述 投票:0回答:3

首先我想为我的英语感到抱歉。

我开始做一些单元测试(我以前从未这样做过,我是编程新手)。

我必须使用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.

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

java unit-testing amazon-web-services mockito verify
3个回答
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
投票

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

组织对你的考试有很大帮助; 做这样的事情:

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 和模拟对象,但有时简单地使用尽可能多的真实对象进行测试是值得的。当您的协作者简单、直接、没有副作用并且不需要复杂的初始化或设置时尤其如此。仅在简化测试设置或验证时才使用模拟。

© www.soinside.com 2019 - 2024. All rights reserved.