10

別のスレッドで機能するメソッドをテストしようとしていますが、単純化すると次のようになります。

public void methodToTest()
{
    Thread thread = new Thread()
    {
        @Override
        public void run() {
            Clazz.i = 2;
        }
    };
    thread.start();
}

私の単体テストでは、Clazz.i == 2 をテストしたいのですが、スレッドが値を変更する前にアサートが実行されると思うので、これを行うことはできません。別のスレッドを使用してテストし、結合を使用して待機することを考えましたが、それでも機能しません。

SSCCE:

@Test
public void sscce() throws InterruptedException
{
    Thread thread = new Thread()
    {
        @Override
        public void run() {
            methodToTest()
        }
    };
    thread.start();     
    thread.join();  
    AssertEquals(2, Clazz.i);
}

public static class Clazz
{
    public static int i = 0;
}

これは、テストのメイン コードが 2 番目のスレッドを待機 (結合) しているスレッドを作成するが、2 番目のスレッドは作業を実行せず、別のスレッドを作成して作業を実行してから終了し、最初のスレッドを続行するためだと思います。スレッド、3 番目のスレッドはClazz.i = 2アサーションの後に実行します。

最初のスレッドが開始するスレッドと、そのスレッドが開始するスレッドを待機するようにするにはどうすればよいですか?

4

3 に答える 3

5

で作成されたスレッドへの参照がなければ、methodToTest単純にできません。Java には、「この特定の期間中に生成されたスレッド」を見つけるためのメカニズムはありません (たとえ存在したとしても、それを使用するのは間違いなく醜いメカニズムです)。

ご覧のとおり、次の 2 つの選択肢があります。

  • methodToTest生成されるスレッドを待ちます。もちろん、これを明示的に非同期アクションにしたい場合は、うまくできません。
  • から新しく作成されたスレッドを返しますmethodToTest。これにより、呼び出し元は必要に応じてそれを待つことができます。

2 番目の選択肢は、いくつかの異なる方法で定式化できることに注意してください。たとえば、非同期作業を行うさまざまな方法を使用するFuture自由を拡張したい場合は、スレッドではなく抽象のようなオブジェクトを返すことができます。methodToTestおそらく、すべての非同期タスクを内部で実行するように強制するグローバル タスク プールを定義し、アサーションをチェックする前にプール内のすべてのタスクが終了するのを待つこともできます。ExecutorServiceこのようなタスク プールは、 、 、またはThreadGroupその他の任意の数の形式をとることができます。最終的にはすべて同じことを行いますが、多かれ少なかれ環境に適している可能性があります。主なポイントは、呼び出し元に新しく作成されたスレッドへのアクセスを明示的に付与する必要があるということです。何らかの方法で。

于 2016-01-29T02:42:13.567 に答える
3

スレッドが異なる操作を実行しているように見えるため、CountDownLatchを使用して問題を解決できます。

メイン スレッドでa を宣言し、CountDownLatchこのラッチ オブジェクトを他のスレッドに渡します。メインスレッドで await() を使用し、他のスレッドでラッチをデクリメントします。

メインスレッド: (最初のスレッド)

CountDownLatch latch = new CountDownLatch(2);
/* Create Second thread and pass the latch. Pass the same latch from second 
   thread to third thread when you are creating third thread */
try {
    latch.await();
} catch (InterruptedException e) {
    e.printStackTrace();
}

このラッチを 2 番目と 3 番目のスレッドに渡し、これらのスレッドでカウントダウンを使用します

2 番目と 3 番目のスレッドでは、

try {
    // add your business logic i.e. run() method implementation
    latch.countDown();
} catch (InterruptedException e) {
    e.printStackTrace();
}

理解を深めるために、この記事をご覧ください。

ExecutorService invokeAll () API は、他の望ましいソリューションです。

于 2016-01-29T03:30:22.203 に答える
0

ユニットが提供しない機能を単体テストすることはできません。

methodToTest() 最終的にが設定されることを確認したいと言っていますClazz.i=2が、「最終的に」とはどういう意味ですか? 関数は、いつ設定されたかを知る方法を呼び出し元に提供しませmethodToTest()Clazz.i。機能をテストする方法を理解するのに苦労している理由は、モジュールがその機能を提供していないためです。

これは、テスト駆動開発 (TDD) について読む良い機会かもしれません。ここで最初にテストを記述し、次にテストに合格するコードを記述します。最初にテストを書くことで、モジュールに何をさせたいかをより明確に描くことができます。

これには副次的な利点もあります。厳密なTDDを実践すれば(つまり、テストに合格する以外にモジュール コードをまったく書かなければ)、テスト カバレッジは 100% になります。

そして、それは別の副次的な利点につながります: 100% のテスト カバレッジがあれば、恐れることなくリファクタリングできます。

于 2016-01-29T15:21:12.853 に答える