[java] 在正在測試的同一類中模擬私有方法


Answers

不要試圖嘲笑私人的方法,即使你可以使用嘲弄的工具從事欺騙手段。 私人成員是實施細節,您應該可以自由更改。 而是使用非私有的API來鍛煉這個類。 如果這很麻煩的話,考慮把麻煩的代碼移到不同的類中,如果它不存在,並且使用依賴注入來注入麻煩代碼的模擬實現。

Question

我有一個名為MyClass的Java類,我想用JUnit進行測試。 我想測試的公共方法methodB調用同一個類中的私有方法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");
    }

}

謝謝!




使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
    }
}

就我個人而言,我通常只測試公共方法並查看覆蓋報告,以確保所有路徑都以我的私有方法訪問過。 如果我真的需要測試一個私有方法,這是一個需要重構,如上所述的氣味。

你也可以使用反射,但我會覺得這樣做很髒。 如果你真的想要解決方案,讓我知道,我會把它添加到這個答案。




Links