我在运行Junit测试时遇到以下异常。
org.mockito.exceptions.misusing.MissingMethodInvocationException:
when()需要一个参数,该参数必须是模拟'上的方法调用。 例如:
when(mock.getArticles()).thenReturn(articles);
此外,此错误可能会显示,因为:
- 你存在以下任何一个:final / private / equals()/ hashCode()方法。这些方法无法进行存根/验证。
- 里面的时候()你不会在模拟上调用方法,而是在其他一些对象上调用方法。
- 模拟类的父级不公开。这是模拟引擎的限制。
醇>
以下是我的代码,并在第二个when语句时抛出异常。我不认为我的测试代码没有违反异常声明的内容。我花了一段时间,但无法弄清楚。有人可以帮忙吗?我需要测试的是getPermProducts方法。在getPermProducts方法中,我想忽略isTempProduct方法。所以,当p1出现时,我希望它返回false,当p2出现时,我希望它返回true等等。
@Named(ProductManager.NAME)
public class ProductManager {
@Resource(name = ProductService.NAME)
private ProductService productService;
public List<Product> getPermProducts(Set<Product> products) {
Iterator<Product> it = products.iterator();
List<Product> cProducts = new ArrayList<Product>();
Product p;
while (it.hasNext()) {
p = it.next();
if (!isTempProduct(p)) {
cProducts.add(p);
}
}
return cProducts;
}
public Boolean isTempProduct(Product product) {
if (product instanceof PermProduct) {
return false;
}
Set<ProductItems> pItems = product.getProductItems();
if (pItems.isEmpty()) {
return false;
}
Iterator<ProductItem> itr = pItems.iterator();
while (itr.hasNext()) {
if (itr.next() instanceof TempItem) {
return true;
}
}
return false;
}
public Product getProduct(Integer productId) {
Product p = productService.getProduct(productId);
return p;
}
}
@RunWith(MockitoJUnitRunner.class)
public class ProductManagerTest {
@InjectMocks
private ProductManager mockProductManager;
@Mock
private ProductService mockProductService;//not being used here
private static final Integer PRODUCT_ID_1 = 1;
private static final Integer PRODUCT_ID_2 = 2;
@Test
public void getProduct(){
Product p1 = mock(PermProduct.class);
p1.setProductId(PRODUCT_ID_1);
when(mockProductManager.getProductId()).thenReturn(PRODUCT_ID_1);
when(mockProductManager.isTempProduct(p1)).thenReturn(false);
Product p2 = mock(TempProduct.class);
p2.setProductId(PRODUCT_ID_2);
when(mockProductManager.isTempProduct(p2)).thenReturn(true);
List<Product> products = Mock(List.class);
products.add(p1);
products.add(p2);
Iterator<Product> pIterator = mock(Iterator.class);
when(prodcuts.iterator()).thenReturn(pIterator);
when(pIterator.hasNext()).thenReturn(true, true, false);
when(pIterator.next()).thenReturn(p1, p2);
asserEquals(1, mockProductManager.getPermProducts(products).size());
}
}
解决方案:我根据enterbios的答案更新了我的测试。我使用了部分嘲讽,但正如enterbios建议的那样,我们应该避免它,但有时我们需要它。我发现我们可以同时使用非模拟和部分模拟类。
@RunWith(MockitoJUnitRunner.class)
public class ProductManagerTest {
@InjectMocks
private ProductManager productManager;//not being used here
@Mock
private ProductService mockProductService;//not being used here
@Spy
private OtherService other = new OtherService();//not being used here
@InjectMocks
final ProductManager partiallyMockedProductManager = spy(new ProductManager());
private static final Integer PRODUCT_ID_1 = 1;
private static final Integer PRODUCT_ID_2 = 2;
@Test
public void getProduct() {
Product p1 = new PermProduct();
p1.setProductId(PRODUCT_ID_1);
Product p2 = new Product();
p2.setProductId(PRODUCT_ID_2);
List<Product> products = new ArrayList<Product>();
products.add(p1);
products.add(p2);
doReturn(false).when(partiallyMockedProductManager).isTempProduct(p1);
doReturn(true).when(partiallyMockedProductManager).isTempProduct(p2);
assertEquals(1, partiallyMockedProductManager.getPermProducts(products).size());
verify(partiallyMockedProductManager).isTempProduct(p1);
verify(partiallyMockedProductManager).isTempProduct(p2);
}
}
答案 0 :(得分:3)
您的mockProductManager实际上不是模拟,而是ProductManager类的实例。你不应该嘲笑一个被测对象。从测试对象模拟一些方法的方法是使用间谍,但我建议你不要使用它们,甚至不要考虑它们,除非你与一些丑陋的遗留代码作斗争。 我认为你的第二个&#39;当&#39;应该用断言替换,如:
assertFalse(mockProductManager.isTempProduct(p1));
因为您真正要在此测试中检查的是,对于PermProduct的所有实例,productManager.isTempProduct(p1)是否返回false。要验证某些方法调用/对象状态的结果,您应该使用断言。为了让您的断言生活更轻松,您可以查看一些有用的库,如Hamcrest或FEST(http://docs.codehaus.org/display/FEST/Fluent+Assertions+Module)。我认为FEST对于初学者来说更简单。