0

呼び出しているオブジェクトからイベントを受け取ることを期待するテストを書いています。具体的には、(オープン ソースの Granados プロジェクトを使用して) SSH 経由で AIX マシンに接続するオブジェクトを呼び出してから切断し、切断中に発生する OnConnectionClosed イベントを確実に受け取りたいと考えています。簡単そうに思えますが、私は過去にこのようなテストをたくさん書いてきましたが、今回は、スレッドに関連していると思われる奇妙な動作が発生しています。

基本的に、私が呼び出したオブジェクトは、呼び出し元とは別のスレッドで「OnConnectionClosed」イベントを発生させています。私が見ているのは、UI から [テストのデバッグ] を選択してテストを実行すると成功するが、[テストの実行] を選択すると失敗することです (デバッグの実行中にブレークポイントが設定されていなくても)。グーグルで検索したところ、デフォルトでは MSTest ホストがシングル スレッド モードで実行されているが、設定を変更することでマルチ スレッド モードで実行できることを示していると思われるこの投稿が見つかりました。これは私の問題を論理的に解決するように聞こえましたが、もちろんそうではありませんでした.

私が遭遇した他のいくつかの投稿も、MSTest が単にバックグラウンド スレッドを監視していないと思わせます (そのため、それらによって発生したイベントは「聞いていません」)。これも理にかなっており、デバッグモードで動作しているように見え、上記の修正はその問題を論理的に解決するはずなので、なぜ動作しないのか混乱しています. スレッドを正しく処理していない可能性がありますが、その場合でもデバッグ モードで問題が発生すると予想されます。

他の誰かが同様の方法で何かをテストしようとしましたか? もしそうなら、同様の問題に遭遇しましたか? もしそうなら、どのように解決しましたか?

関連する単体テスト コードを以下に貼り付けました (セキュリティ上の理由から接続情報を削除しました)。

[TestClass]
public class SSHReaderTests
{
    private bool received = false;
    private delegate bool SimpleFunc();

    [TestInitialize]
    public void MyTestInitialize()
    {
        received = false;
    }

    [TestMethod]
    public void Should_raise_OnReaderConnectionClosed_event_after_successful_connection_is_disconnected()
    {
        IReader reader = new SSHReader();

        reader.OnReaderConnectionClosed += delegate
                                     {
                                         received = true;
                                     };

        reader.Connect("*****", "*****", "*****");

        //Assert.IsTrue(reader.IsConnected);

        reader.Disconnect();

        //Assert.IsFalse(reader.IsConnected);

        Assert.IsTrue(WaitUntilTrue(delegate {
            return received; }, 30000, 1000));
    }

    private static bool WaitUntilTrue(SimpleFunc func, int timeoutInMillis, int timeBetweenChecksInMillis)
    {
        Stopwatch stopwatch = new Stopwatch();
        stopwatch.Start();

        while(stopwatch.ElapsedMilliseconds < timeoutInMillis)
        {
            if (func())
                return true;

            Thread.Sleep(timeBetweenChecksInMillis);
        }
        return false;
    }
}
4

2 に答える 2

2

System.Threading 名前空間の WaitHandle クラスを使用します。AutoResetEvent または ManualResetEvent のいずれかです。この 2 つの違いは、AutoResetEvent では、設定されるたびに 1 つのスレッドを続行できるのに対し、ManualResetEvent では、待機中のすべてのスレッドを設定時に解放することです。

あなたの例が機能しない理由は、コンパイラの最適化に関係しています。コードは実際には、一見しただけで考えられるようにはコンパイルされません。ほとんどの場合、コンパイラはローカル変数をレジスタに配置するようなことを行い、チェックするループ中に実際にフェッチすることはありません。volatile キーワードを使用すると、この種のことを回避できますが、詳細については、スレッド化と同時実行性について読むことを強くお勧めします。http://www.bluebytesoftware.comにあるJoe Duffy のブログは、始めるための優れたリソースです。近日中に出版される彼の本、Concurrency Programming on Windows を強くお勧めします。

于 2008-10-20T21:09:18.603 に答える
0

あなたが求めているものとは正確には異なりますが、CHESSと呼ばれるMS Researchプロジェクトをチェックすることで、いくつかの実行可能な解決策または少なくともアイデアを見つけることができます. これは、.net でのマルチスレッド同時実行テスト用です。

于 2008-10-20T21:46:18.653 に答える