如何使用Typhoon

时间:2015-11-30 17:05:38

标签: ios objective-c integration-testing dependency-management typhoon

我尝试使用KIF编写集成测试。我的问题是:

  

如何为特定视图控制器注入stubbed,mock或fake依赖项?

每个使用依赖关系的视图控制器,如数据模型,http客户端,商店管理器等,都来自ModelAssembly,ApplicationAssembly,ManagerAssmebly。

在故事板上,对于登录视图,我有一个键路径,包含值" loginViewController"。

创建视图控制器:

ViewControllersAssembly.h

@interface ViewControllersAssembly : TyphoonAssembly
@property (nonatomic, strong) ModelAssembly *modelAssembly;

- (id)loginViewController;
@end

ViewControllersAssembly.m

@implementation ViewControllersAssembly
- (UIViewController *)loginViewController {
return [TyphoonDefinition withClass:[LoginViewController class] configuration:^(TyphoonDefinition *definition) {
    [definition injectProperty:@selector(userModel) with:[self.modelAssembly userModel]];
}];

}

UserModel有登录方法

- (RACSingnal*)loginWithEmail:(NSString*)email password:(NSString*)password;

现在在集成测试目标中我有类似的类:

LoginTests.h

@interface LoginTests : KIFTestCase
@property (nonatomic, strong) UserModel *fakeUserModel;
@end

LoginTests.m

@implementation LoginTests

- (void)beforeAll {
    self.fakeDataModel = [self mockDataModel];
}

- (void)testLogin {
    [self.fakeDataModel mockNextResponse:[RACSignalHelper getGeneralErrorSignalWithError:[[NSError alloc] initWithDomain:@"http://some.com" code:452 userInfo:nil]]];
    [tester waitForViewWithAccessibilityLabel:@"loginScreen"];

    [tester enterText:@"user@gmail.com" intoViewWithAccessibilityLabel:@"emailAdress"];
    [tester enterText:@"asd123" intoViewWithAccessibilityLabel:@"password"];
    [tester tapViewWithAccessibilityLabel:@"loginButton"];

    [tester tapViewWithAccessibilityLabel:@"OK"];
    // for example error code 542 we should display alert with message "User Banned"
    // now somehow check that UIAlertView localizedDescription was "User Banned" 
}

- (FakeUserModel *)mockUserModel {
    ModelAssembly *modelAssembly = [[ModelAssembly assembly] activate];
    TyphoonPatcher *patcher = [[TyphoonPatcher alloc] init];
    [patcher patchDefinitionWithSelector:@selector(userModel) withObject:^id{
        return [FakeUserModel new];
     }];

    [modelAssembly attachDefinitionPostProcessor:patcher];
    return [modelAssembly userModel];
}

FakeUserModel是覆盖UserModel类的类,为下一个被调用的请求增加了存根响应的可能性。

该解决方案不起作用。

我应该如何以及在哪里通过FakeUserModel?

1)我想访问注入的实例

2)注入的实例必须是FakeUserModel类型,它只在集成测试目标中。

3)我不想修改集成测试的生产代码。

2 个答案:

答案 0 :(得分:1)

单元测试

如果您希望使用测试double替换给定类的所有依赖项,从而与其协作者隔离测试类,则这将是一个单元测试。只需实例化一个测试实例,将测试双打(模拟,存根等)作为协作者传递。

集成测试

如果您希望使用测试双精度修补程序集中的一个或多个实例,为了使系统进入集成测试所需的状态,Typhoon提供了几种方法。

您可以修补组件,如下所示:

MiddleAgesAssembly* assembly = [[MiddleAgesAssembly assembly] activate];

TyphoonPatcher* patcher = [[TyphoonPatcher alloc] init];
[patcher patchDefinitionWithSelector:@selector(knight) withObject:^id{
    Knight* mockKnight = mock([Knight class]);
    [given([mockKnight favoriteDamsels]) willReturn:@[
        @"Mary",
        @"Janezzz"
    ]];

    return mockKnight;

}];

[assembly attachPostProcessor:patcher];

Knight* knight = [(MiddleAgesAssembly*) factory knight]

有关此方法的更多信息,请参阅用户指南的Integration Testing部分。

<强>模块化

或者你可以模块化你的程序集,并使用子类或替代实现来激活,它提供了某些类的另一个实现,例如:

UIAssembly *uiAssembly = [[UIAssembly new] 
    activateWithCollaboratingAssemblies:@[
        [TestNetworkComponents new], //<--- Patched for testing
        [PersistenceComponents new]];

SignUpViewController* viewController = [uiAssembly signUpViewController];

有关此方法的更多信息,请参阅用户指南的modularization section

答案 1 :(得分:1)

如果要修补故事板使用的程序集并使用Plist集成进行初始化,则可以通过调用以下方式使该程序集成为默认值:

[yourAssembly makeDefault];

您可以通过调用以下方法在测试用例中获取此程序集:

[yourAssembly defaultAssembly];

之后,您可以轻松修补一些定义。在测试开始之前让你的程序集默认是很重要的,所以也许app delegate会是一个很好的地方。这是probalby不是最好的解决方案,但看起来你想要实现一些全局的装配访问。