2013-04-12 3 views
0

Я пишу приложение iOS, используя MonoTouch, у которого есть много информации для ввода на нескольких разных экранах. Информацию A, B и C можно ввести на экране 1, но мне нужно отобразить Info B на экране 3 вместе со входами для информации X, Y, Z и т. Д. Пользователь может перейти от экрана 1 к экрану 7, а затем вернуться к экрану 3.Как тестировать классы интеграции/интеграции, основанные на NSNotificationCenter (в MonoTouch)?

Итак, я создал статический класс для получения всей информации (через 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); 
    } 
} 

Все это прекрасно работает.

Мой вопрос: как я могу его интегрировать/интегрировать? Из-за природы приложения/политики/yadda-yadda у меня должно быть покрытие на 100%. Вот что я пробовал и с чем сталкивался.

Проблема, которую я имею пытаюсь написать интеграционный тест для этого является обеспечение того, если сделать запрос для информации, что я получаю ответ с информацией А.

[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'd, прежде чем он сможет получить ответ, но я поставил точку останова в методе IFC.HandleRequestA, и он никогда не будет вызван. Через проверку я вижу, что уведомления регистрируются в Центре по умолчанию, но они, похоже, не увольняются.

В дополнение ко всему этому, как я могу проверить, чтобы уведомление было получено в течение определенного промежутка времени, а если нет, пропустите тест? Я пытался добавить переменную класса:

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 Я изменил класс МОК от статических к нестатическому (а также методам), и что решено проблема с обработчиками не вызываются. Это означает, что я должен был создать его в AppDelegate и TestFixtureSetUp, но я думаю, что мы сможем жить с этим. /EDIT2

+0

(http://stackoverflow.com/q/ 4373079/639445) – miek

ответ

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); 
} 
+0

Я не знал о ManualResetEvent. Это фиксирует часть второй проблемы. – miek

Смежные вопросы