如何在iOS 5运行时为基于状态的测试存根/注入视图控制器?

问题描述:

我正在寻找一种“最佳实践”/“低测试摩擦”的方式来对基于AppDelegate类的视图控制器进行基于状态的测试。目前,下面提供了一种简单的方法来存储我自己的UIViewController(使用ocmock),当它发生在类的方法内部时。如何在iOS 5运行时为基于状态的测试存根/注入视图控制器?

-(FirstViewController *)getFirstViewController 
{ 
    if (self.viewController1) 
    { return self.viewController1; } 

    self.viewController1 = [[FirstViewController alloc] initWithNibName:@"FirstViewController" bundle:nil]; 

    return self.viewController1; 
} 

的第一个问题我有这个-Is来,踩灭/注入我自己的模拟视图控制器用于测试的有效方法是什么? (似乎工作很好,但我不知道这是如何专业人士如何进行基于状态的测试今天)

我有下一个问题 - 是否有效保持视图控制器的1副本像这样(只从头开始为应用程序的生命创建一次)?

**注 - 我的依赖注入这一点,但我的init已经足够大,只是注射的导航控制器和标签栏控制器,所以这不是这个大类的选择黯然

如果它的根视图控制器,你应该让你的应用程序委托的属性:

@interface MyAppDelegate : NSObject <UIApplicationDelegate> 
@property(retain)FirstViewController *firstViewController; 
@end 

@implementation MyAppDelegate 
@synthesize firstViewController; 
... 
@end 

除非你正在测试的方法是你初始化firstViewController的方法,你不需要任何种类的延迟加载方法。只要让应用程序的委托在您的测试,创建FirstViewController一个实例,并将其分配给您的委托财产,并定义测试:如果你想要模拟出任何你就是控制器

-(void)testSomething { 
    MyAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate]; 
    FirstViewController *firstViewController = [[FirstViewController alloc] init]; 
    appDelegate.firstViewController = firstViewController; 

    // test some app delegate method 
    ... 
} 

测试中,你可以做到这一点,以及:

-(void)testSomething { 
    MyAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate]; 
    id mockController = [OCMockObject mockForClass:[FirstViewController class]]; 
    appDelegate.firstViewController = mockController; 

    [[mockController expect] someControllerMethod]; 

    // test some app delegate method 
    ... 

    [mockController verify]; 
} 

依赖注入并不需要你通过init方法注入所有依赖关系。有理由为什么这是首选,但这是另一个讨论。

您可以简单地将-setFirstViewController:方法添加到您的类中。你会在你的测试中使用该方法来注入你的模拟。如果你不喜欢你的应用程序中的方法,你可以在测试代码中使用一个类别添加方法。

+0

公平一点 - 但如果我删除此方法,并做基本的setter注入如何做有关游戏瓦特/我的问题的第二部分时,新起来的这些依赖AppDelegate的? – 2012-03-18 22:12:38

+0

您仍然可以将lazy-init保存在上面包含的getter中。只要确保在你的测试中你打电话给我第一次调用getter之前建议的setter。 – 2012-03-19 15:52:08

对于这种测试,我会让它像你一样,略有不同。

第一个视图控制器的延迟加载封装了一个属性。

在.h文件中

@interface AppDelegate { 
    FirstViewController *viewController1_; 
} 

然后

@property (nonatomic, readonly) FirstViewController viewController1; 

在.m文件

- (FirstViewController *)viewController1 { 
    if (!viewController1_) { 
     viewController1_ = [[FirstViewController alloc] initWithNibName:@"FirstViewController" bundle:nil]; 
    } 

    return viewController1_; 
} 

2阶如果我想注入模拟对象,我用KVC在我测试代码

[appDelegateUnderTest setValue:mockViewController forKey:@"viewController1_"]; 

问候,