我正在使用 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);
}
}
这一切都很好。
我的问题是如何进行单元/集成测试? 由于 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