这是类Person
public class Person {
// ...
public String getInfo(String key)
return key; //for brevity
}
}
另一个类Student
依赖于Person
(请注意,当前实现是问题的一部分,我们无法修改这两个类)
public class Student {
private String copyFirstName;
private String otherInfo;
private Person person;
Student(Person p) {
person = p;
copyFirstName = person.getInfo("firstName")
if (copyFirstName == null || copyFirstName.equals("")) { //entry point A
throw new SomethingError("message here");
}
otherInfo = person.getInfo("bio")
if (otherInfo == null || otherInfo.equals("")) { // entry point B
throw new SomethingError("message here");
}
}
}
上面的类可能看起来不切实际,但请将其视为我们无法改变的问题的一部分。
目标是完全覆盖测试中的所有线路。为此,我计划进行两个测试来覆盖两个 if
语句并模拟方法 getInfo
,同时注意传递的参数,以便我知道何时跳过 "构造函数第二次测试的入口点 A”。
理想情况下,这将是我的 JUnit 类
public class StudentTest {
private Person person;
private Student student;
private Person mockedPerson;
@Before
public void init()
throws SomethingError {
person = new Person();
student = new Student();
mockedPerson = Mockito.mock(Person.class);
}
@Test(expected=SomethingError.class)
public void myTest1()
throws SomethingError {
Mockito.when(mockedPerson.getInfo("firstName"))
.thenAnswer(
new Answer<String>(){
@Override
public String answer(InvocationOnMock invocation) {
String arg = invocation.getArgumentAt(0, String.class);
System.out.println(arg);
if (arg.equals("firstName")) {
return null;
}
return person.getInfo(arg); // default value
}});
try {
new Student(mockedPerson);
fail();
} catch (MultilingualException e) {
Mockito.reset(mockedPerson); // not sure if this works
assertEquals(e.getMessage(), "message here");
}
}
@Test(expected=SomethingError.class)
public void myTest2()
throws SomethingError {
Mockito.when(mockedPerson.getInfo("bio"))
.thenAnswer(
new Answer<String>(){
@Override
public String answer(InvocationOnMock invocation) {
String arg = invocation.getArgumentAt(0, String.class);
System.out.println(arg);
if (arg.equals("bio")) {
return "";
}
return person.getInfo(arg); // defaul value for firstName
}});
try {
new Student(mockedPerson);
fail();
} catch (MultilingualException e) {
Mockito.reset(mockedPerson); // not sure if this works
assertEquals(e.getMessage(), "message here");
}
}
}
但它没有按预期工作。 myTest1
成功输入第一个 if
语句。但随后在 myTest2
上,第二个 if
语句被错过。奇怪的是,myTest2
的 @Override 下面的所有内容都会被错过,并立即进入其 catch
中。
我还尝试创建 Person
的单独模拟实例,但它仍然具有相同的覆盖结果。
如何测试并覆盖构造函数中从同一方法获取评估值的两个连续 if
语句?
编辑
我确实尝试了下面最简单的方法,但似乎 .when
并不关心参数的值是什么,因为第二个测试仍然触发第一个 if
.
@Test(expected=SomethingError.class)
public void test() throws SomethingError {
Mockito.when(mockedPerson.getInfo("firstName")).thenReturn(null);
try {
new Student(mockedPerson);
} catch (SomethingError e) {
assertEquals(e.getMessage(), "message here");
}
}
@Test(expected=SomethingError.class)
public void test2() throws SomethingError {
Mockito.when(mockedPerson.getInfo("bio")).thenReturn(null);
try {
new Student(mockedPerson);
} catch (SomethingError e) {
assertEquals(e.getMessage(), "message here");
}
}
最佳答案
不需要那个私有(private)学生;
,实际上你可以摆脱测试类中的所有这些字段,你的测试应该尽可能独立,在你的情况下你可以在每个测试方法中一起进行模拟和 stub 。
使用
ArgumentMatchers.eq("firstName");
要检查参数值是否相等,如果需要,您也可以使用答案变体,但在您的情况下,这要简单得多。
以下是您的测试的样子:
@Test
public void newStudentWithPersonWithNullFirstName() {
Person person = Mockito.mock(Person.class);
Mockito
.doReturn(null)
.when(person)
.getInfo(ArgumentMatchers.eq("firstName"));
SomethingError actual = Assert
.assertThrows(SomethingError.class, () -> new Student(person));
Assert.assertEquals("firstName is null or empty", actual.getMessage());
}
@Test
public void newStudentWithPersonWithEmptyFirstName() {
Person person = Mockito.mock(Person.class);
Mockito
.doReturn("")
.when(person)
.getInfo(ArgumentMatchers.eq("firstName"));
SomethingError actual = Assert
.assertThrows(SomethingError.class, () -> new Student(person));
Assert.assertEquals("firstName is null or empty", actual.getMessage());
}
@Test
public void newStudentWithPersonWithNullBio() {
Person person = Mockito.mock(Person.class);
Mockito
.doReturn("Foo")
.when(person)
.getInfo(ArgumentMatchers.eq("firstName"));
Mockito
.doReturn(null)
.when(person)
.getInfo(ArgumentMatchers.eq("bio"));
SomethingError actual = Assert
.assertThrows(SomethingError.class, () -> new Student(person));
Assert.assertEquals("bio is null or empty", actual.getMessage());
}
@Test
public void newStudentWithPersonWithEmptyBio() {
Person person = Mockito.mock(Person.class);
Mockito
.doReturn("Foo")
.when(person)
.getInfo(ArgumentMatchers.eq("firstName"));
Mockito
.doReturn("")
.when(person)
.getInfo(ArgumentMatchers.eq("bio"));
SomethingError actual = Assert
.assertThrows(SomethingError.class, () -> new Student(person));
Assert.assertEquals("bio is null or empty", actual.getMessage());
}
@Test
public void newStudentWithPersonSuccess() {
Person person = Mockito.mock(Person.class);
Mockito
.doReturn("Foo")
.when(person)
.getInfo(ArgumentMatchers.eq("firstName"));
Mockito
.doReturn("Bar")
.when(person)
.getInfo(ArgumentMatchers.eq("bio"));
Student actual = new Student(person);
Assert.assertEquals("Foo", actual.getCopyFirstName());
Assert.assertEquals("Bar", actual.getOtherInfo());
}
覆盖范围:
关于java - Mockito 重复方法调用正在测试的同一函数/构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60929781/