如何单元/集成测试依赖于NSNotificationCenter的类(在MonoTouch中)
本文关键字:的类 NSNotificationCenter MonoTouch 依赖于 何单元 单元 集成测试 | 更新日期: 2023-09-27 18:09:07
我正在使用MonoTouch编写一个iOS应用程序,该应用程序需要在多个不同的屏幕上输入大量信息。信息A、B和C可以在屏幕1上输入,但我需要在屏幕3上显示信息B以及信息X、Y、Z等的输入。用户可以从屏幕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);
}
}
这一切都很好。
我的问题是我如何单元/集成测试它?由于应用程序/政策/之类的性质,我必须有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
你可以试试这样做吗:
[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);
}