在做单元测试的时候,经常会遇到mock类的方法的情景。在写单测过程中,遇到一些问题,比较困惑,便做了一些测试,并得出一个结论:
在mock类的方法时,当符合 (mock参数).equals(实际调用过程中的参数)时,才可以mock成功;当参数为基本类型时,可以使用angLong等。

下面是测试的欢乐时间啦:
首先看测试基础类:

public class Person {
    private String name;
    private Integer age;
    private Person friend;
}

public class PersonService {

    public void showFriendInfo(Person person){
        System.out.println("show friend info ...");
        showInfo1(new Person("shoren", 22));
        showInfo2(person.getFriend());
    }

    public void showInfo1(Person person){
        System.out.println("show info1 ...");
    }

    public void showInfo2(Person person){
        System.out.println("show info2 ...");
    }

    public void showPersonInfo(Person person){
        System.out.println("show person info ...");
        showName("shoren");
        showName2(person.getName());

    }

    public void showName(String name){
        System.out.println("show name1 : " + name);
    }

    public void showName2(String name){
        System.out.println("show name2 : " + name);
    }

}    

先看参数为基本类型时:

1. 参数为基本类型时,使用any都可以成功mock。

    @Test
    public void testShowPersonInfoUsingAny(){
        final Person person = new Person("manyao", 23);

        new NonStrictExpectations(personService){{
            Deencapsulation.invoke(personService, "showName", anyString);
            Deencapsulation.invoke(personService, "showName2", anyString);
        }};
        personService.showPersonInfo(person);
    }

结果为

show person info ...

2. 参数为基本类型,mock时传入真实的值,且与之前值相等,可以mock成功。

    @Test
    public void testShowPersonInfoUsingData(){
        final Person person = new Person("manyao", 23);

        new NonStrictExpectations(personService){{
            Deencapsulation.invoke(personService, "showName", new String("shoren"));
            Deencapsulation.invoke(personService, "showName2", new String("manyao"));
        }};
        personService.showPersonInfo(person);
    }

结果为:

show person info ...

3. 参数为基本类型,mock时传入真实的值,若实际调用值与之不相等,则mock失败。

    @Test
    public void testShowPersonInfoUsingData2(){
        final Person person = new Person("manyao", 23);

        new NonStrictExpectations(personService){{
            Deencapsulation.invoke(personService, "showName", new String("tata"));
            Deencapsulation.invoke(personService, "showName2", person.getName());
        }};
        personService.showPersonInfo(person);
    }

结果为

     show person info ...
     show name1 : shoren

得出结论:如果参数为基本类型,则mock参数为anyXXX 或者 与实际调用的参数值相等时,可以mkco成功。

再来看参数为复杂类型:

4. 参数为复杂参数时,使用any做类型转换,mock失败。

    @Test
    public void testShowFriendUseAny(){
        final Person person = new Person("manyao", 23);
        person.setFriend(new Person("friend", 24));

        new NonStrictExpectations(personService){{
            Deencapsulation.invoke(personService, "showInfo1", (Person)any);
            Deencapsulation.invoke(personService, "showInfo2", (Person)any);
        }};
        personService.showFriendInfo(person);
    }

结果为

     java.lang.IllegalArgumentException: Invalid null value passed as argument 0
     at jmockito.PersonServiceTest$4.<init>(PersonServiceTest.java:92)
     at jmockito.PersonServiceTest.testShowFriendUseAny(PersonServiceTest.java:91)
     at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
     at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:78)
     at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212)
     at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68)
     at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)

5. 参数为复杂参数,mock参数为具体值时,mock参数 equals 实际调用值时,mock成功。

    @Test
    public void testShowFriendUseData(){
        final Person person = new Person("manyao", 23);
        person.setFriend(new Person("friend", 24));

        new NonStrictExpectations(personService){{
            Deencapsulation.invoke(personService, "showInfo1", new Person("shoren", 22));
            Deencapsulation.invoke(personService, "showInfo2", person.getFriend());
        }};
        personService.showFriendInfo(person);
    }

结果为

     show friend info ...
     show info1 ...

到这里,似乎可以得出这样一个结论,mock内部调用方法时,其mock参数与外部参数的关系,应该与实际执行时,参数的关系一致。即实际调用中,showInfo2的参数是person.getFriend(),
所以,在mock方法showInfo2时,其参数也应该是person.getFriend()。
如果是这样的话,mock方法showInfo1时,又该如何呢?在Person中添加equals方法测试一下。

6. 参数为复杂参数时,(mock参数).equals(实际参数)时,mock成功。

    @Test
    public void testShowFriendUseData1(){
        final Person person = new Person("manyao", 23);
        person.setFriend(new Person("friend", 24));

        new NonStrictExpectations(personService){{
            Deencapsulation.invoke(personService, "showInfo1", new Person("shoren", 22));
            Deencapsulation.invoke(personService, "showInfo2", new Person("friend", 24));
        }};
        personService.showFriendInfo(person);
    }

结果为

show friend info ...

7. 参数为复杂参数时,修改equals方法,总是return true时。不论mock参数如何,mock成功.

	 @Test
    public void testShowFriendUseData2(){
        final Person person = new Person("manyao", 23);
        person.setFriend(new Person("friend", 24));

        new NonStrictExpectations(personService){{
            Deencapsulation.invoke(personService, "showInfo1", new Person());
            Deencapsulation.invoke(personService, "showInfo2", new Person());
        }};
        personService.showFriendInfo(person);
    }

结果为

 show friend info ...

综上,我们得出结论:
在mock类的方法时,当符合 (mock参数).equals(实际调用过程中的参数)时,才可以mock成功;当参数为基本类型时,可以使用angLong等。

当然,像这一类的问题,如果要了解清楚,最好还是去阅读源代码。暂时没有时间做这件事。

posted on 2017-03-02 16:28  漫夭  阅读(1814)  评论(0编辑  收藏  举报