起初我想抱歉我的英语。
我开始进行一些单元测试(我以前从未这样做过,我是编程中的新人)。
我必须使用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.
有人可以告诉我,我做错了吗?
答案 0 :(得分:0)
您应该模拟和验证的是IO[(A, B)]
依赖项:
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));
}
对象一起调用就足够了。
答案 1 :(得分: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));
}
}
答案 2 :(得分:0)
唯一应该被模拟的东西 - 如果有的话 - 是ObjectMapper和databaseController。一个人只能嘲笑协作者对象,而且几乎从不测试被测系统/类(在SUT上“间谍”的情况非常罕见)。并且取决于ObjectMapper是什么以及它的操作是多么透明,你可能真的不想甚至嘲笑它。此外,由于您的实现代码是通过直接调用构造函数来实例化ObjectMapper而编写的,因此您甚至无法模拟它。
虽然我喜欢使用Mockito和模拟对象,但有时候用尽可能多的真实对象进行测试是值得的。当您的协作者简单,直接,没有副作用,并且不需要复杂的初始化或设置时,尤其如此。只有在简化测试设置或验证时才使用模拟。