3

私はmockitoを使って練習していますが、ローカルオブジェクトのメソッドの呼び出しに依存するメソッドをテストする方法に少しこだわっています。次の例を参照してください。

public class Worker {          

    public void work() {
                   Vodka vodka = new Vodka();
                   vodka.drink();
     }
}

この労働者は、仕事をする代わりに、飲むのが好きです。しかし、私は彼が仕事中に飲んでいることを証明するためのテストを追加したいと思います。ただし、メソッドworkが呼び出されたときにメソッドdrink()が呼び出されていることを確認する必要があるため、これを行う方法はありません。これはテストが不可能であるということで、あなたは私に同意すると思います。そのため、テストを開始する前に依存関係を解消する必要があります。これが私の最初の疑問です、あなたはそのような依存関係を壊す最良の方法は何だと思いますか?ウォッカオブジェクトのスコープをグローバルに変更しただけでは、良くないと思います(クラスの他の部分に公開したくありません)。私は次のような工場を作ることを考えました:

public class Worker {          

    private VodkaFactory vodkaFactory = new VodkaFactory();


    public void work() {
                   Vodka vodka = vodkaFactory.getVodka();
                   vodka.drink();
     }
}

依存関係を正しく解除したかどうかはわかりませんが、ここで実行したいのは、work()の実行時にdrink()メソッドが呼び出されることをテストすることです。私は運が悪かったのでこれを試しました:

@Test
    public void
    does_the_worker_drink_while_working
    () {
        VodkaFactory vodkaFactory = mock(VodkaFactory.class);
        Vodka vodka = mock(Vodka.class);
        Worker worker = new Worker();
        worker.work();
        when(vodkaFactory.getVodka()).thenReturn(vodka);
        verify(vodka,times(1)).drink();
    }

ファクトリをモックすると、ファクトリによって新しいウォッカオブジェクトが作成されたことがいつ検出されます。しかし、そのメソッドがメソッドdrink()を1回呼び出すことを確認したい場合、mockitoは次のように通知します。

Wanted but not invoked:
vodka.drink();
-> at testing_void_methods_from_local_objects.WorkerSpecification.does_the_worker_drink_while_working(WorkerSpecification.java:22)
Actually, there were zero interactions with this mock.

私は正しくスタブしていないか、何か間違ったことをしています。このテストを完了するための手を差し伸べてください。また、そのようなテスト不可能な方法をテストするための最良の方法を教えてください。

mockitoには、メソッド呼び出しをモックするために使用されるdoAnswer()というメソッドがあることを知っていますが、この場合に役立つと思いますか?どのように使用すればよいですか?

アップデート:

私はwhen()前に呼び出されるように提案に従っていますwork()。また、クラスの外部からファクトリを設定できるようにしようとしています。

@Test
public void
does_the_worker_drink_while_working
() {
    VodkaFactory vodkaFactory = mock(VodkaFactory.class);
    Vodka vodka = mock(Vodka.class);
    Worker worker = new Worker();
    when(vodkaFactory.getVodka()).thenReturn(vodka);
    worker.work();
    verify(vodka,times(1)).drink();
}

これが本番コードになりました。

public class Worker {          


        private VodkaFactory vodkaFactory;

        public void work() {
                       Vodka vodka = vodkaFactory.getVodka();
                       vodka.drink();
         }

         public void setVodkaFactory(VodkaFactory vodkaFactory) {
               this.vodkaFactory = vodkaFactory;
         }

私が得る例外は次のとおりです。

 java.lang.NullPointerException
        at testing_void_methods_called_from_local_objects.Worker.work(Worker.java:9)

これは言う行ですvodka.drink()

申し訳ありませんが、私はまだ何が問題なのか混乱しています。

4

5 に答える 5

3

ワーカーはここで独自のファクトリクラスを作成します。

private VodkaFactory vodkaFactory = new VodkaFactory();

作成しているモックはワーカーインスタンスから完全に切り離されているため、相互作用がありません。それを機能させるには、ファクトリを「外部」から、たとえばコンストラクタインジェクションを介してワーカーに注入する必要があります。

これがレガシーコードの場合、リフレクションを使用してプライベートファクトリインスタンスをモックされたインスタンスに置き換えることができます。

JB Nizetがコメントで指摘しているように、モックセットアップworkはすでに呼び出された後に行われます。物事を正しくするために、それを利用するコードを呼び出す前に、モックを注入してセットアップします。

于 2013-03-11T23:02:39.553 に答える
3

vodkaFactoryを設定する必要があります。

@Test
public void
does_the_worker_drink_while_working() {
    VodkaFactory vodkaFactory = mock(VodkaFactory.class);
    Vodka vodka = mock(Vodka.class);
    Worker worker = new Worker();
    when(vodkaFactory.getVodka()).thenReturn(vodka);

    //call your setter        
    worker.setVodkaFactory(vodkaFactory);

    worker.work();
    verify(vodka,times(1)).drink();
}
于 2013-03-12T02:28:06.400 に答える
1

テストしようとしているコードに論理エラーがあります。VodkaFactoryクラス内にインスタンスを作成Workerし、さらにそのフィールドをプライベートにしたためです。

VodkaFactory最善の解決策は、クラスの外部からへの参照を渡すことです。

public class Worker {          

    private VodkaFactory vodkaFactory;

    public void work() {
                   Vodka vodka = vodkaFactory.getVodka();
                   vodka.drink();
     }

     public void setVodkaFactory(VodkaFactory vf) {
           vodkaFactory = vf;
     }

}

これで、@ Testで、 setterVodkaFactoryを使用してモックされたインスタンスを渡すことができます。setVodkaFactory

于 2013-03-11T23:03:01.290 に答える
1

答えよりもコメントです。when(vodkaFactory.getVodka()).thenReturn(vodka);ファクトリを注入可能な依存関係にすることに加えて、モックを操作する前にモックをトレーニングすることもできます。worker.work();

于 2013-03-11T23:07:03.440 に答える
1

以下は、依存関係の実装から分離してメソッドを実行する完全なJMockit単体テストです。Worker#work()Vodka

@Test
public void workTest(@Mocked final Vodka mockBeverage)
{
    new Worker().work();

    new Verifications() {{ mockBeverage.drink(); times = 1; }};
}
于 2013-03-12T20:14:31.693 に答える