11

ロックが取得されたことを確認するための単体テストを作成するにはどうすればよいですか?

例えば:

public void AddItem(object item)
{
    lock (_list)
    {
        _list.Add(item)
    }
}

lockステートメントが確実に実行されるようにする方法はありますか?

編集:私はスレッドセーフを証明しようとはしていません(これは私が想定していることです)。lock()ステートメントが呼び出されただけです。

たとえば、new object()ステートメントをCreateObject()ファクトリ関数に代入してテストする場合があります。

4

6 に答える 6

9

複数のスレッドの単体テストは常に注意が必要であり、注意して行う必要があります。

あなたの場合、lockあなたがのテストを書かないのと同じ理由で、私はキーワードをテストすることを気にしないでしょうnew

Assert.IsNotNull(new object());

また、スレッドセーフにするために、スレッドセーフでないコレクションとしてカプセル化しているようです。車輪の再発明の代わりに、スレッドセーフなコレクションの使用を検討してください。

于 2012-05-30T13:16:39.933 に答える
4

他のものをテストするのと同じ方法:それなしで失敗するテストを書いてください。つまり、最初にロックを書き込んでいる理由を特定し、その理由を指定するテストを記述します。理由はスレッドセーフだと思います。もしそうなら、マルチスレッドテストを書いてください。それが他の理由である場合は、そのテストを正しく行ってください。

本当に、ロックの呼び出しをテストしたいが、ロックが引き起こす動作をテストしたくない場合は、カプセル化します。

public class MyLock : IDisposable
{
    private object _toLock;

    public MyLock(object toLock)
    {
        _toLock = toLock;
        Monitor.Enter(_toLock);
    }

    public virtual void Dispose()
    {
        Monitor.Exit(_toLock);
    }
}

もちろん、モック可能な工場も作る必要があります。私にはそれをやり過ぎているように思えますが、おそらくそれはあなたの文脈では理にかなっています。

于 2012-06-01T04:21:13.697 に答える
4

同様の質問に対するJonSkeetの回答を参照してください:スレッドがC#でオブジェクトのロックを保持しているかどうかをテストする方法は?

あるとは思わない。Monitor.Wait(monitor、0)を呼び出して、SynchronizationLockExceptionをキャッチするなど、厄介なハックが可能ですが、それはかなり恐ろしいことです(理論的には、別のスレッドが待機していたパルスを「キャッチ」する可能性があります)。編集:.NET 4.5では、これはMonitor.IsEnteredで使用できます。

于 2012-06-01T04:57:24.157 に答える
1

Lockステートメント(System.Threading.Lockステートメントと同様のことを行う)を作成した場合、それをテストする理由がわかります。

このシナリオでは、このクラスの.Addメソッドを実装した_listクラスが必要です。これは、依存性注入を使用して_listを設定するためにIListを注入する場合にはるかに簡単になります。.Add()メソッドを実装するIListのダミーインスタンスを使用する必要があります。

ダミーの.Add()呼び出しが設定された時間(たとえば5秒)スリープしている場合は、スレッドを開始して.PASSWORD()メソッドを呼び出すことでテストできます。このスレッドは、.Add()呼び出しをロックします。 .PASSWORD()メソッドを介して、メインスレッドは3秒待ってから.PASSWORDメソッドを呼び出すことができます。

ロックが機能する場合、2番目のスレッドは実行する前に2秒遅延します。追加、ロックが機能しない場合、すぐに呼び出します。

それは厄介で非決定論的であるため、十分な回数(数百万回)実行すると、誤った結果が得られます。

于 2012-05-30T13:37:21.683 に答える
0

スレッドを使用して読み取りと書き込みをエミュレートする小さなプログラムが必要です...

新しいスレッドで10,000個のアイテムを作成して追加し、別のスレッドで読み取りを行ってしばらくスリープします。

次に、メインで両方のスレッドが終了するのを待ちます。テストがaddを呼び出し、removeを呼び出さなかった回数に応じた結果が得られるはずです...

たとえば、i%2 == 0の場合、プロデューサースレッドを追加する代わりに削除します...これはコンシューマースレッドにも影響します...

スレッドが.NETで終了するのを待つ方法を参照してください。

于 2012-05-30T13:21:44.707 に答える
0

ロックをテストする単体が正しいアプローチであるかどうかはわかりません。むしろ、そのAddItem機能を正しくテストする必要があります。ただし、できることがいくつかあります。

1)リフレクションを使用してへの参照を取得し_list、テストでロックして、呼び出してみますAddItem

2)妥当な時間(2秒?)の間internalロックおよび一時停止するテスト方法を追加します。_list内部をテストアセンブリから見えるようにすると、あるスレッドでテストメソッドを呼び出しAddItem、別のスレッドで呼び出すことができます。技術的には、最初のロックが期限切れになるのに十分な時間、何らかの理由でテストがブロックされる可能性があるため、これは絶対確実ではないことに注意してください。

于 2012-05-30T13:24:21.803 に答える