8

Action メソッドで BeginInvoke をテストする方法を探しています。メソッドはバックグラウンド スレッドで実行されるため、実際に完了したりコールバック メソッドを呼び出したりするタイミングを知る方法はありません。アサーションを行う前にコールバックが呼び出されるまでテストを待機させる方法を探しています。

次の Presenter クラスでは、データがフェッチされたときにビューを更新するバックグラウンド スレッドで PopulateView を呼び出しており、ビューのプロパティが正しく初期化されていることをアサートしようとしていることがわかります。

NUnit と Moq を使用しています。

public class Presenter
{
    private IView _view;
    private IService _service;
    public Presenter(IView view, IService service)
    {
        _view = view;
        _service = service;

        Action action = PopulateView;  
        action.BeginInvoke(PopulateViewCallback, action);
    }
    private void PopulateViewCallback(IAsyncResult ar)
    {
            try
            {
                Action target = (Action)ar.AsyncState;
                target.EndInvoke(ar);
            }
            catch (Exception ex)
            {
                Logger.Instance.LogException("Failed to initialize view", ex);
            }
    }

     private void PopulateView()
     {
          Thread.Sleep(2000); // Fetch data _service.DoSomeThing()
          _view.Property1 = "xyz";
     }  
}
4

3 に答える 3

9

テスト時に必要な動作を挿入できるように、コードを抽象化します。

public class MethodInvoker
{
    public virtual void InvokeMethod(Action method, Action callback)
    {
         method.BeginInvoke(callback, method);
    }
}

このバージョンは非同期です。テスト時には、単純にブロッキング バージョンを作成できます。

public class TestInvoker
{
    public IAsyncResult MockResult { get; set; }

    public override void InvokeMethod(Action method, Action callback)
    {
         method();
         callback(MockResult);
    }
}

次に、コードを次のように変更します。

 // Inject this dependency
Invoker.InvokeMethod(PopulateView, PopulateViewCallback);

実行時は非同期です。テスト時に、呼び出しをブロックします。

于 2011-05-04T15:49:07.717 に答える
2

BeginInvoke()待機に使用できるを返しますIAsyncResult

IAsynchResult ar = action.BeginInvoke(...);
ar.AsyncWaitHandle.WaitOne();
于 2011-05-04T15:43:11.957 に答える
0

メソッドが呼び出されていることを確認する必要はありません。代わりに、最終結果をテストします。この場合は、_view.Propert1=="xyz"です。

これは非同期呼び出しであるため、値が設定されたことを定期的にアサートするループが必要になる場合があります。また、テストまたはチェックのタイムアウトも必須です。そうしないと、テストが失敗することはありません(スタックするだけです)。

スリープをスキップするために、アクション(PopulateView)をスタブアウトすることを検討してください。

于 2011-05-04T15:43:25.170 に答える