Mockito验证单元测试-需要但未调用,实际上,与此模拟没有交互

xnifntxz  于 2022-11-08  发布在  其他
关注(0)|答案(3)|浏览(173)

一开始我想为我的英语道歉。
我开始做一些单元测试(我以前从来没有做过,我是一个编程新手)。
我必须使用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.

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

bvuwiixz

bvuwiixz1#

您应该模拟和验证的是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对象调用的就足够了。

rnmwe5a2

rnmwe5a22#

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

luaexgnf3#

唯一应该被模拟的东西--如果有的话--就是ObjectMapper和databaseController。(“监视”SUT的情况非常罕见)。根据ObjectMapper是什么以及它的操作有多透明,您可能真的不想嘲笑它。此外,因为您的实现代码是通过直接调用构造函数来示例化ObjectMapper编写的,所以您甚至不能模仿它。
虽然我喜欢使用Mockito和mock对象,但有时候用尽可能多的真实对象进行测试是值得的。当你的合作者简单、直接、没有副作用、不需要复杂的初始化或设置时,这一点尤其正确。只有当mock简化了测试设置或验证时,才使用它。

相关问题