17

MyClassJUnit でテストしたいという名前の Java クラスがあります。テストするパブリック メソッド は、同じクラスmethodAのプライベート メソッド を呼び出して、methodBどの条件付きパスに従うかを決定します。私の目標は、 のさまざまなパスの JUnit テストを作成することmethodAです。また、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");
    }

}

ありがとう!

4

5 に答える 5

4

モック ツールを使用してトリックを実行できる場合でも、プライベート メソッドをモックしようとしないでください。プライベート メンバーは実装の詳細であり、自由に変更する必要があります。代わりに、非プライベート API を使用してクラスを実行してください。これが面倒な場合は、問題のあるコードを別のクラスに移動することを検討してください (まだ存在しない場合)。依存性注入を使用して、問題のあるコードのモック実装を挿入します。

于 2013-10-31T08:24:48.920 に答える
0

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

個人的には、通常はパブリック メソッドのみをテストし、カバレッジ レポートを見て、すべてのパスがプライベート メソッドでアクセスされていることを確認します。プライベート メソッドを本当にテストする必要がある場合は、上記のようにリファクタリングが必要な匂いです。

リフレクションを使用することもできますが、それを行うと汚いと感じます。その解決策が本当に必要な場合はお知らせください。この回答に追加します。

于 2013-10-31T06:09:56.610 に答える
0
import org.easymock.EasyMock;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest({ MyClass.class })
public class MyClassTest {

// Class Under Test
MyClass cut;

@Before
public void setUp() {

    // Create a new instance of the service under test (SUT).
    cut = new MyClass();

    // Common Setup
    // TODO
}

@Test
public void testMethodA() throws Exception {

    /* Initialization */
    CustomObject object2 = PowerMock.createNiceMock(CustomObject.class);
    CustomObject object1 = PowerMock.createNiceMock(CustomObject.class);

    MyClass partialMockCUT = PowerMock.createPartialMock(MyClass.class,
            "methodB");
    long response = 1;

    /* Mock Setup */
    PowerMock
            .expectPrivate(partialMockCUT, "methodB",
                    EasyMock.isA(CustomObject.class),
                    EasyMock.isA(CustomObject.class)).andReturn(true)
            .anyTimes();

    /* Mock Setup */

    /* Activate the Mocks */
    PowerMock.replayAll();

    /* Test Method */

    String result = partialMockCUT.methodA(object1, object2);

    /* Asserts */
    Assert.assertNotNull(result);
    PowerMock.verifyAll();

}

}
于 2013-11-08T15:05:06.303 に答える
-1

private メソッドをモックするには、 powermockが必要です
。サンプル コードは次のようになりますが、実行していません。

    import org.mockito.Mockito;
    import org.powermock.api.mockito.PowerMockito;
    import org.powermock.modules.junit4.PowerMockRunner;

    @RunWith (PowerMockRunner.class)
    public class MyClassTest  {

        @Test
        public void test_MyClass_methodA_enters_if_condition()  {
            final MyClass myClass = Mockito.mock (MyClass.class);
            CustomObject object1 = new CustomObject("input1");
            CustomObject object2 = new CustomObject("input2");
            Mockito.when (myClass.methodB(object1, object2)).thenReturn (true);
            Mockito.when (myClass.methodA(object1, object2)).thenCallRealMethod ();

            assertEquals(myClass.methodA(object1, object2), "Result");
        }
    }
于 2013-10-31T06:16:46.240 に答える