3

コードのどこかでメソッドを変更したため、テストが異常に失敗することはありませんでしたが、JMock はそうではないと考えているようです。

この問題を最小限の粗雑さまで煮詰めました。これは次のようになります。

import java.util.Collection;
import java.util.Collections;
import java.util.List;

import org.jmock.Expectations;
import org.jmock.Mockery;
import org.jmock.lib.legacy.ClassImposteriser;
import org.junit.Test;

public class TestMocking {

    @Test
    public void test() {
        Mockery mockery = new Mockery() {{
            setImposteriser(ClassImposteriser.INSTANCE);
        }};
        final Owner owner = mockery.mock(Owner.class);
        final RealThing thing = mockery.mock(RealThing.class, "thing");

        mockery.checking(new Expectations() {{
            oneOf(owner).getThing(); will(returnValue(thing));
            oneOf(thing).method(); will(returnValue(Collections.emptyList()));
        }});

        owner.getThing().method();

        mockery.assertIsSatisfied();
    }

    public static interface Owner {
        BaseThing getThing();
    }

    public static interface BaseThing {
        Collection<?> method();
    }

    public static interface RealThing extends BaseThing {
        List<?> method();
    }
}

(編集:これは、クラスがなくなっても ClassImposteriser を使用するようになりました。これは、その imposteriser なしでまったく同じコードを実行でき、テストに合格することを実証したかったためです。)

これを実行した結果:

unexpected invocation: thing.method()
expectations:
  expected once, already invoked 1 time: owner.getThing(); returns <thing>
  expected once, never invoked: thing.method(); returns <[]>
what happened before this:
  owner.getThing()

つまり、予期されたthing.method()が呼び出されなかったときの「予期しない」thing.method()です。これは、マルチスレッド クラスがモック オブジェクトに対してテストされているときに発生することを以前に確認しましたが、今回はすべて単一のスレッドで発生しています。私はそのようなオブジェクトをモックしなかったにもかかわらず、JMock が最初のメソッド呼び出しから何らかの形で別のモック オブジェクトを返しているようです。

より具体的な型を返すオーバーライドされたメソッドを削除すると、それはなくなりますが、明らかにそれはできません。同様に、ClassImposteriser の使用を取り除けば問題は解決しますが、実際のテストでモックしているオブジェクトの 1 つは他の人のクラスです。1 回のテストで 2 つの Mockery インスタンスを使用できると思いますが、それ以外はアイデアがありません。

4

1 に答える 1

2

クラス (静的) メソッドの非表示は、インスタンス メソッドのオーバーライドとまったく同じようには機能しません。ここで JMock のせいではないことを証明するには、次のようにします。

public class test3 {
public static void main(String[] args) {
    Owner owner = new Owner();
    owner.getThing().method(); //Like how you execute your test
    RealThing thing = new RealThing();
    thing.method(); //Similar to your mock.
}

private static class Owner {
    private BaseThing thing = new RealThing();

    public BaseThing getThing() {
        return thing;
    }
}

private static class BaseThing {
    public static void method() {
        System.out.println("Basething!");
    }
}

private static class RealThing extends BaseThing {
    public static void method() {
        System.out.println("Realthing!");
    }
}
}

method()printの 2 つの呼び出しが異なることに注意してください。どちらも RealThing のインスタンスですが、異なるメソッドを呼び出します。呼び出される静的メソッドは、サブクラスまたはスーパークラスのどちらから呼び出されるかによって異なります。上記の最初の呼び出しでは、メソッドは BaseClass として宣言されているため、RealClassBaseClass.method()のインスタンスであるにもかかわらず呼び出されます。への 2 番目の呼び出しmethod()は RealClass として宣言されているため、RealClass.method()呼び出されます。

したがって、JMock からの結果は有効です。呼ばれたのmethod()は、あなたが期待していたものと同じではありませんでした。

これについての私の説明を気にしないでください。ここで読んでください:http://docs.oracle.com/javase/tutorial/java/IandI/override.html


修正 (優先BaseThing.method())、変更:

final RealThing thing = mockery.mock(RealThing.class, "thing");

に:

final BaseThing thing = mockery.mock(RealThing.class, "thing");

または、 を使用する場合は、次のようRealThing.method()に変更します。

owner.getThing().method()

に:

RealThing thing = (RealThing)owner.getThing();
thing.method();
于 2012-12-13T00:01:33.083 に答える