ここではクラスがあります Person
public class Person {
// ...
public String getInfo(String key)
return key; //for brevity
}
}
そして、別のクラスには、Student
上の依存関係を持つPerson
(現在の実装では、問題の一部であり、我々はこれら2つのクラスを変更できないことに注意してください)
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");
}
}
}
クラスは、上記の非現実的に見えるが、我々は変更できないという問題の一部としてそれを取ることがあります。
目標は、テストのすべての行を完全にカバーを持つことです。これを行うために、私は2つのカバーするために2つのテストする予定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
の文を逃しています。@Override以下不思議なことのすべてがmyTest2
逃し、すぐにそのに移行しますcatch
。
私はまた、個々の嘲笑のインスタンスを作成しようとしたPerson
が、それはまだ同じカバレッジ結果を持っています。
どのようにして、2つの連続した試験とカバーする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;
、actualyあなたのテストクラスのそれらのフィールドのすべてを取り除くことができ、あなたのテストでは、可能な限り独立したとしてもsould、そしてあなたのケースでは、あなたはモックを行うことができ、それぞれの試験方法でalltoghetherをstubing。使用する
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());
}
カバレッジ: