使用testng和mockito编写单元测试。我通常会通过使用不同的值/条件检查所有方案,在同一测试方法中练习几次调用一种方法。
请不要考虑我提供的逻辑和设计。这只是示例,以清楚我要做什么。
审查下面的代码。
public class Human {
private String name;
private boolean parent;
private List<Human> childs = new ArrayList<>();
public String getName() {
return name;
}
public boolean isParent() {
return parent;
}
public void setParent(boolean parent) {
this.parent = parent;
}
public void addChild(List<Human> childs) {
this.childs = childs;
}
public List<Human> getChilds() {
return childs;
}
}
public class Validator {
public boolean isParent(Human human) {
if (null == human) {
return false;
}
if (human.isParent()) {
return true;
}
if (human.getChilds().size() > 0) {
return true;
}
return false;
}
}
IM通过使用Mockito编写验证器iSparent方法的测试用例。
公共类ValtorAtest {
public void testIsParent() throws Exception {
Validator validator = Mockito.spy(new Validator());
Human human = Mockito.mock(Human.class);
Mockito.when(human.isParent()).thenReturn(false);
boolean isParent = validator.isParent(human);
Mockito.verify(human).getChilds();
Mockito.when(human.isParent()).thenReturn(true);
isParent = validator.isParent(human);
Mockito.verify(human).getChilds();
}
在这里,我想验证getChilds()切勿呼叫第二种方法呼叫validator.isparent(human),因为嘲笑人类集在call human.isparent();
时返回true我使用 mockito.verifyZeroInteractions(),但它说失败据我了解, mockito.verifyZeroInteractions()通过所有测试检查。不仅用于特定的方法调用。
我想知道是否有某种方法可以验证某些情况下的方法,并且在同一测试方法中,方法对相同的情况进行了调用。或者我应该在一种测试方法中练习测试一个方案。
这是一个很好的做法,最好是"每一种测试方法"(请参阅每个功能/方法我应该写多少个单元测试?)
从技术上讲,仍然可以使用Mockito.reset(...)
重置模拟,但是这是官方文档对此所说的:
Smart Mockito用户几乎不使用此功能,因为他们知道这可能是测试不良的迹象。 通常,您无需重置模拟,只需为每种测试方法创建新的模拟。
而不是
reset()
,请考虑在冗长的,过度指定的测试上写作简单,小且集中的测试方法。在测试方法中间,第一个潜在的代码气味是reset()
。这可能意味着您正在测试太多。遵循您的测试方法的耳语:"请让我们小小的专注于单一行为"。
请参阅https://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/mockito/mockito.html#17
验证方法可以接受第二个参数,您可以在其中指定调用该方法的次数。您可以用它来说该方法从未被调用,一次调用,两次等。
例如:
import static org.mockito.Mockito.never;
...
public void testIsParent() throws Exception {
Validator validator = Mockito.spy(new Validator());
Human human = Mockito.mock(Human.class);
Mockito.when(human.isParent()).thenReturn(false);
boolean isParent = validator.isParent(human);
Mockito.verify(human).getChilds();
Mockito.when(human.isParent()).thenReturn(true);
isParent = validator.isParent(human);
Mockito.verify(human, never()).getChilds();
}
此处的文档在这里:http://static.javadoc.io/org.mockito/mockito-core/2.9.0/org/mockito/mockito/mockito.html#4
我想指出,这个问题严重滥用模拟,用于测试可以轻松,干净地测试而无需任何模拟的事物。
这是测试的样子:
public class ValidatorTest {
final Validator sut = new Validator();
@Test
public void checkThatNoHumanIsNotAParent() {
boolean isParent = sut.isParent(null);
assertFalse(isParent);
}
@Test
public void checkHumanThatIsNotAParent() {
Human notAParent = new Human();
boolean isParent = sut.isParent(notAParent);
assertFalse(isParent);
}
@Test
public void checkParentHumanWithNoChildIsAParent() {
Human parentWithNoChildren = new Human();
parentWithNoChildren.setParent(true);
boolean isParent = sut.isParent(parentWithNoChildren);
assertTrue(isParent);
}
@Test
public void checkHumanNotMarkedAsParentButWithChildIsAParent() {
Human humanWithChildren = new Human();
Human child = new Human();
humanWithChildren.addChild(child);
boolean isParent = sut.isParent(humanWithChildren);
assertTrue(isParent);
}
}
这些测试完整的练习所有四种情况。它们显然比使用模拟的版本要好得多。最后,请注意,Mockito的文档(在如何编写良好测试的页面中)还说,值对象(例如Human
)应 not 被模拟。