簡體   English   中英

Mockito 重復方法調用正在測試的同一函數/構造函數

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM