[英]Mockito Repetitive Method Call on the same Funciton/Constructor being Tested
這是類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
之下的所有內容都被遺漏了,並立即進入了它的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 Student student;
,實際上您可以擺脫測試類中的所有這些字段,您的測試應該盡可能獨立,並且在您的情況下,您可以在每個測試方法中一起進行模擬和存根。 用
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());
}
覆蓋范圍:
可能您還需要為第二個單元測試模擬Mockito.when(mockedPerson.getInfo("firstName"))
。 為簡潔起見,您“省略”了getInfo
的代碼,但我覺得它返回空/空,因此,為第一個 if 檢查拋出異常。
看看你的代碼,做一個簡單的:
Mockito.when(mockedPerson.getInfo("firstName"))
.thenReturn("");
可能工作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.