在正在测试的同一类中模拟私有方法

我有一个名为MyClass的Java类,我想用JUnit进行测试。 公共方法methodA ,我想测试调用私有方法, methodB ,在同级别来确定要遵循的条件路径。 我的目标是为methodA的不同路径编写JUnit测试。 此外, methodB调用一个服务,所以我不希望它在我运行JUnit测试时被实际执行。

模拟methodB并控制其返回以便我可以测试'methodA'的不同路径的最佳方法是什么?

我更喜欢在写模拟时使用JMockit,所以我特别感兴趣的是适用于JMockit的任何答案。

这是我的示例类:

public class MyClass  {

    public String methodA(CustomObject object1, CustomObject object2)  {

        if(methodB(object1, object2))  {
            // Do something.
            return "Result";
        }

        // Do something different.
        return "Different Result";

    }

    private boolean methodB(CustomObject custObject1, CustomObject custObject2)  {

        /* For the sake of this example, assume the CustomObject.getSomething()
         * method makes a service call and therefore is placed in this separate
         * method so that later an integration test can be written.
         */
        Something thing1 = cobject1.getSomething();
        Something thing2 = cobject2.getSomething();

        if(thing1 == thing2)  {
            return true;
        }
        return false;
    }

}

这是我到目前为止:

public class MyClassTest  {
    MyClass myClass = new MyClass();

    @Test
    public void test_MyClass_methodA_enters_if_condition()  {
        CustomObject object1 = new CustomObject("input1");
        CustomObject object2 = new CustomObject("input2");

        //  How do I mock out methodB here to return true?

        assertEquals(myClass.methodA(object1, object2), "Result");
    }

    @Test
    public void test_MyClass_methodA_skips_if_condition()  {
        CustomObject object1 = new CustomObject("input1");
        CustomObject object2 = new CustomObject("input2");

        //  How do I mock out methodB here to return false?

        assertEquals(myClass.methodA(object1, object2), "Different Result");
    }

}

谢谢!


给你要求的答案(使用JMockit的部分模拟):

public class MyClassTest
{
    @Tested MyClass myClass;

    @Test
    public void test_MyClass_methodA_enters_if_condition() {
        final CustomObject object1 = new CustomObject("input1");
        final CustomObject object2 = new CustomObject("input2");

        new NonStrictExpectations(myClass) {{
            invoke(myClass, "methodB", object1, object2); result = true;
        }};

        assertEquals("Result", myClass.methodA(object1, object2));
    }

    @Test
    public void test_MyClass_methodA_skips_if_condition() {
        final CustomObject object1 = new CustomObject("input1");
        final CustomObject object2 = new CustomObject("input2");

        new NonStrictExpectations(myClass) {{
            invoke(myClass, "methodB", object1, object2); result = false;
        }};

        assertEquals("Different Result", myClass.methodA(object1, object2));
    }
}

不过,我不会推荐这样做。 一般来说, private方法不应该被嘲笑。 相反,模拟被测单元的实际外部依赖性(在这种情况下是CustomObject ):

public class MyTestClass
{
    @Tested MyClass myClass;
    @Mocked CustomObject object1;
    @Mocked CustomObject object2;

    @Test
    public void test_MyClass_methodA_enters_if_condition() {
        new NonStrictExpectations() {{
            Something thing = new Something();
            object1.getSomething(); result = thing;
            object2.getSomething(); result = thing;
        }};

        assertEquals("Result", myClass.methodA(object1, object2));
    }

    @Test
    public void test_MyClass_methodA_skips_if_condition() {
        new NonStrictExpectations() {{
            object1.getSomething(); result = new Something();
            object2.getSomething(); result = new Something();
        }};

        assertEquals("Different Result", myClass.methodA(object1, object2));
    }
}

不要试图嘲笑私人方法,即使你可以使用嘲弄工具进行欺骗。 私人成员是实施细节,您应该可以自由更改。 而是使用非私人API来锻炼班级。 如果这很麻烦,考虑将麻烦的代码移到不同的类中(如果它不存在的话),并使用依赖注入来注入麻烦代码的模拟实现。


使methodB成为一个单独的类的成员,并在MyClass具有对该类的私有引用。

public class MyClass  {
    private MyOtherClass otherObject = new MyOtherClass();

    public String methodA(CustomObject object1, CustomObject object2)  {

        if(otherObject.methodB(object1, object2))  {
            // Do something.
            return "Result";
        }

        // Do something different.
        return "Different Result";

    }
}

class MyOtherClass {
    public boolean methodB(CustomObject custObject1, CustomObject custObject2)  {
        // Yada yada code
    }
}

就我个人而言,我通常只测试公共方法并查看覆盖报告以确保所有路径都以我的私有方法访问过。 如果我真的需要测试一个私有方法,那是一种需要重构的嗅觉,就像我上面的那样。

你也可以使用反射,但我会觉得这样做很脏。 如果你真的想要解决方案,让我知道,我会添加到这个答案。

链接地址: http://www.djcxy.com/p/75221.html

上一篇: Mock private method in the same class that is being tested

下一篇: How to zero unused memory to reduce VM snapshot size