0

我正在编写单元测试。而且我无法测试一个函数,因为它调用了 keyWindow

UIWindow* window = [UIApplication sharedApplication].keyWindow;

并且 keyWindow 返回 nil(我没有任何窗口)。但我需要返回任何东西,但为零。

我使用类别手动设置 keyWindow 值,但这不起作用

@interface UIApplication(UnitTest)
- (id)getKeyWindow;
@end

@implementation UIApplication(UnitTest)
- (id)getKeyWindow
{
    return [self keyWindow];
}
@end

// compiler error: lvalue required as left operand of assignment
[[UIApplication sharedApplication] getKeyWindow] = [[UIWindow alloc] init]; 

你会代替我做什么?

4

3 回答 3

3

当您开始接近框架类时,Apple 并不容易测试您的代码。我发现 UIApplication 特别困难,因为它的单例性质,以及框架在设置过程中为您创建实例的事实。此类问题的解决方案通常取决于您的测试方式;例如,您的测试中是否有有效的 UIApplication 对象?如果您使用的是 OCUnit,那么 [UIApplication sharedApplication] 本身可能会返回 nil,除非您已将测试目标设置为在应用程序包中运行(老实说,我从未设法让它工作)。

一种选择是根本不对此进行测试。大多数情况下,您与主窗口的交互相对简单,对这段代码的测试就像在测试您自己的代码一样测试 UIKit 框架。这是一个风格决定,取决于您如何构建代码,让这个小区域未经测试(或更恰当地说,未经测试自动化)的舒适程度,以及编写测试的难度。

如果您有与您决定确实需要测试的 UIWindow 对象相关的代码,我建议您以一种您可以在测试中控制的方式封装功能。您可以通过为您的应用创建 UIApplication 的子类来实现此目的,该子类从自定义方法返回 UIWindow 对象。在您的代码中使用此方法,而不是直接访问 window 属性,并在您的测试中覆盖此方法以返回您喜欢的任何内容。

于 2010-11-08T20:11:36.877 回答
0

我能够通过调动应用程序委托设置器来模拟委托对象并验证某些期望,例如 applicationDidBecomeActive。

id<UIApplicationDelegate> delegate = [MyCustomDelegate alloc] init];
UIApplication *app = [UIApplication alloc] init];
app.delegate = delegate;
//results in "There can only be one UIApplication" error

反而:

@implementation AppDelegateTests {

- (void)testAppDelegate {
     //perform swizzle on [UIApplication class] and method @selector(setDelegate:) with
     //[self class] and at the bottom @selector(swizzledSetDelegate:)

     id<UIApplicationDelegate> delegate = [MyCustomDelegate alloc] init];

     //Here's the magic, this line actually calls [UIApplication setDelegate] and not the swizzledSetDelegate method below. 
     //If you don't understand this, look up how swizzling works and hopefully you can wrap your head around it. The logic is quite mind-bendy.
     [self swizzledSetDelegate:delegate];

     //here set up your mock on the delegate and verify state of things
}

- (void)swizzledSetDelegate:(id<UIApplicationDelegate>)delegate {
     //do nothing
}

}

请注意,此示例对我需要测试的内容非常自定义,您需要考虑要模拟什么以及是否可能。

于 2013-08-03T01:47:21.893 回答
0

您可以创建新的窗口对象:

UIWindow* window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];

于 2019-04-30T10:11:20.587 回答