0

私は、MonoTouch を使用して iOS アプリケーションを作成しています。これには、かなりの数の異なる画面に入力する必要のある多くの情報があります。情報 A、B、および C は画面 1 に入力される可能性がありますが、情報 X、Y、Z などの入力と共に情報 B を画面 3 に表示する必要があります。ユーザーは、画面 1 から画面 7 までスキップして、画面 3 に戻ることができます。

そこで、(NSNotifications 経由で) すべての情報を受け取り、それをキャッシュする静的クラスを作成しました。また、さまざまな画面から (再び NSNotifications を介して) 情報の要求をリッスンし、関連する情報を (プライベートな静的メソッドで) キャッシュからパッケージ化し、応答として別の通知を送信します。このクラスには常に最新の情報が含まれている必要があるため、ユーザーがジャンプする画面に関係なく最新の情報が含まれている必要があります。

public static class InformationFlowController
{
    static List<NSObject> _observers;
    static Dictionary<SomeEnum, Object> _data;

    static InformationFlowController()
    {
        _observers = new List<NSObject>();
        _data = new Dictionary<SomeEnum, Object>();

        _observers.Add(NSNotificationCenter.DefaultCenter.AddObserver(Notifications.PayloadA, HandlePayloadA));
        ...
        _observers.Add(NSNotificationCenter.DefaultCenter.AddObserver(Notifications.RequestA, HandleRequestA));
    }

    // receive information A
    static void HandlePayloadA(NSNotification ntf)
    {
        var infoA = (InfoA)ntf.Object;
        if (A == null) { /* throw an exception */ }

        if (_data.ContainsKey(EnumA))
        {
            _data.Remove(EnumA);
        }

        _data.Add(EnumA, infoA);
    }

    // receive request for info A
    static void HandleRequestA(NSNotification ntf)
    {
        InfoA info = null;

        if (_data.ContainsKey(EnumA))
        {
            info = _data.GetValue(EnumA);
        }

        // its up to the receiver what it wants to do if it gets null
        NSNotificationCenter.DefaultCenter.PostNotificationName(Notifications.ResponseA, info);
    }
}

これはすべてうまくいきます。

私の質問は、ユニット/統合テストをどのように行うのですか? app/policy/yadda-yadda の性質上、最大 100% のコード カバレッジが必要です。これが私が試したことと私が遭遇したことです。

このための統合テストを作成しようとしている問題は、情報 A を要求した場合に、情報 A を含む応答が得られるようにすることです。

[Test]
public void HandleRequestForATest()
{
    // setup the data in the IFC here

    NSNotificationCenter.DefaultCenter.AddObserver(Notifications.ResponseA, delegate(NSNotification ntf)
    {
        var info = ntf.Object as InfoA;
        Assert.IsNotNull(info, "Info is null!");
        // some other asserts to check the data within info
    }

    NSNotificationCenter.DefaultCenter.PostNotificationName(Notifications.RequestA, null);        
}

テストは 0 アサートでパスします。ブレークポイントを設定しましたがvar info = ntf.Object as InfoA;、決して触れられません。応答を受信する前に GC が実行されるのではないかと考えましたが、IFC.HandleRequestAメソッドにブレークポイントを設定したところ、呼び出されませんでした。調べてみると、通知が DefaultCenter に登録されていることがわかりますが、起動されていないようです。

それに加えて、特定の時間内に通知が受信されることを確認するにはどうすればよいですか? そうでない場合は、テストに失敗しますか? クラス変数を追加してみました:

bool assertsCompleted = false;

そしてテストを変更します:

[Test]
public void HandleRequestForATest()
{
    // setup the data in the IFC here

    NSNotificationCenter.DefaultCenter.AddObserver(Notifications.ResponseA, delegate(NSNotification ntf)
    {
        var info = ntf.Object as InfoA;
        Assert.IsNotNull(info, "Info is null!");
        // some other asserts to check the data within info
        assertsCompleted = true;
    }

    NSNotificationCenter.DefaultCenter.PostNotificationName(Notifications.RequestA, null);        

    NSTimer.CreateTimer(2, delegate
    {
        if (!assertsCompleted)
        {
            Assert.IsTrue(false, "Notification not received or Asserts not complete!");
        }
    } 
}

ブレークポイントを設定しましたがif (!assertsCompleted)、それもヒットしていません。

助けてください!:)

EDIT2 IFC クラスを静的から非静的 (およびメソッド) に変更し、ハンドラーが呼び出されないという問題を修正しました。つまり、AppDelegate と TestFixtureSetUp でインスタンス化する必要がありましたが、これで問題ないと思います。 /EDIT2

4

1 に答える 1

2

次のようなことを試してみてください:

[Test]
public void HandleRequestForATest()
{
    // setup the data in the IFC here

    var resetEvent = new ManualResetEvent(false);
    InfoA info = null;

    var observer = NSNotificationCenter.DefaultCenter.AddObserver(Notifications.ResponseA, delegate(NSNotification ntf)
    {
        info = ntf.Object as InfoA;
        resetEvent.Set();
    }

    NSNotificationCenter.DefaultCenter.PostNotificationName(Notifications.RequestA, null);        

    Assert.IsTrue(resetEvent.WaitOne(250), "Reset event timed out!");
    Assert.IsNotNull(info, "Info is null!");
    // some other asserts to check the data within info

    //Make sure you do this! I'd put in try-finally block
    NSNotificationCenter.DefaultCenter.RemoveObserver(observer);
}
于 2013-04-12T17:42:54.587 に答える