1

Mockito を使っていたときは、モック化されたインスタンスを簡単に作成できました。しかし、JMockit ではそれほど単純ではないようです。私の考えを説明するために、次の例を使用しましょう。

public class App {
    private String name;

    public App(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

これは非常に単純な不変のラッパーです。Mockito を使用してテストするには、次のようなコードを記述できます。

List<App> mockApps = new ArrayList<App>();
String[] fakeNames = new String[] {"a", "b", "c"};
for (String name : fakeNames) {
    // create a mocked instance
    // I don't care if the class has a default ctor or not
    App mockApp = mock(App);
    when(mockApp.getName()).thenReturn(name);
    // add to the container
    mockApps.add(mockApp);
}

// assertions
for (int i = 0; i < fakeNames.length; i++) {
    assertThat(mockApps.get(i).getName(), is(fakeNames[i]));
}

ただし、JMockit では状況が変わります: (何か見落としているかもしれません)
同じ結果を得るには、次のことを行う必要があります。

@Mocked App app;  // let JMockit kick in for this class
List<App> mockApps = new ArrayList<App>();
String[] fakeNames = new String[] {"a", "b", "c"};
for (final String name : fakeNames) {
    // create a mocked instance
    // DIFFERENCE: I have to use the ctor provided by App class
    // I actually can just pass "name" to the ctor here in this example
    // but let's assume getName() in reality has much more complex logic
    App mockApp = new App(null);
    new NonStrictExpectations(mockApp) {
        mockApp.getName(); result = name;
    }
    mockApps.add(mockApp);
}

// assertions
for (int i = 0; i < fakeNames.length; i++) {
    assertThat(mockApps.get(i).getName(), is(fakeNames[i]));
}

それが正しいアプローチかどうかはわかりませんが、うまくいきます。そして、これは行動ベースのテストと呼ばれていると思います。
質問 1: ctor をバイパスできますか? (単純にすべてのヌルを渡すことができるようですが、そうしたくありません。)

JMockit の状態ベースのテストに関して別の質問があります。

インスタンスを達成するためにこの方法を行う場合:

List<App> mockApps = new ArrayList<App>();
String[] fakeNames = new String[] {"a", "b", "c"};
for (final String name : fakeNames) {
    new MockUp<App> {
        @Mock
        public String getName() {
            return name;
        }
    }
    App mockApp = new App(null);
    mockApps.add(mockApp);
}

すべての mockApp がその名前として「c」を返すため、事態はさらに悪化します。実行時にモック化されたクラスは常に1つしか存在できず、後で定義されたものはすべて前のものに取って代わりますが、これは意味がないと思います。

質問 2 は、状態ベースのテストでさまざまなモック インスタンスを取得できますか?

4

1 に答える 1

3

JMockit では @Injectable を使用して個々のモック インスタンスを作成します。その後、モック化されたインスタンスごとに特定の動作を記録できます。

どちらの質問でも、テスト ケースに対する Mockito アプローチである可能性がある (またはそうでない可能性がある) ものを使用しています。別の例は、解決しようとしている問題を理解するのに役立つ場合があります。

JMockitでやろうとしていることができるかどうかはわかりません。これは、達成しようとしていることを実行するための動的でない方法です。私自身のテストケースのコレクションに注入可能なモックが必要だった場合、私はこのアプローチを採用しました。動作を確認するには十分であることがわかりました。より複雑なテストケースを処理できない場合があることに感謝します。

@Injectable App app1;
@Injectable App app2;

@Test
public void testApps() throws Exception {

    final App [] apps = new App[2];
    final String [] names = {"a", "b"};

    apps[0] = app1;
    apps[1] = app2;

    new NonStrictExpectations() {
        {
            app1.getName();
            result = "a";

            app2.getName();
            result = "b";
        }
    };

    for (int i = 0; i < apps.length; i++){
        System.out.println(apps[i].getName());
    }
}

当たり前のことを述べているかもしれませんが、上記のmockitoテストでは、テストは単にテストケースの構成を検証しているだけで、実際のテストコードはありません.

于 2013-10-17T17:14:00.830 に答える