如何使用Typhoon为集成测试注入伪造的,存根的或模拟的依赖项 [英] How to inject fake, stubbed or mock dependencies for Integration tests using Typhoon

查看:140
本文介绍了如何使用Typhoon为集成测试注入伪造的,存根的或模拟的依赖项的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm trying to write integration tests using KIF. My question is:

如何为特定的视图控制器注入存根,模拟或伪造的依赖关系?

How to inject stubbed, mock or fake dependency for particular view controller?

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

Each view controller using dependencies like a data model, http client, store manager etc. comes from ModelAssembly, ApplicationAssembly, ManagerAssmebly.

在情节提要上,对于登录视图,我有一个键路径,其中包含值"loginViewController".

On storyboard, for login view i have a key path, containing value "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具有登录方法

UserModel have method to login

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

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

Now in integration tests target i have class like:

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 is class that override UserModel class, adding possibility to stub response for next called request.

该解决方案不起作用.

我应该如何以及在哪里传递FakeUserModel?

1)我想访问注入的实例

1) i'd like to have access to injected instance

2)注入的实例必须为FakeUserModel类型,该类型仅在集成测试目标中.

2) injected instance must be of type FakeUserModel, which is only in integration tests target.

3)我不想为集成测试修改生产代码.

3) i don't want to modify production code for integration tests.

推荐答案

单元测试

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

If you wish to replace all dependencies for a given class with a test double, and thus test a class in isolation from its collaborators, this would be a unit test. Simply instantiate an instance for testing, passing in your test doubles (mock, stub, etc) as collaborators.

集成测试

如果您希望使用测试双打来修补装配中的一个或多个实例,以使系统处于集成测试所需的状态,则Typhoon提供了几种方法.

If you wish to patch-out one or more instances in an assembly with a test double, to put the system into the required state for an integration test, Typhoon provides several approaches.

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

You can patch out a component as follows:

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]

有关此方法的更多信息,请参见

More information on this approach can be found in the Integration Testing section of the user guide.

模块化

或者,您可以对程序集进行模块化,并通过提供某些类的另一种实现的子类或替代实现来激活,例如:

Alternatively you could modularize your assembly, and activate with a sub-class or alternative implementation, that provides another implementation of certain classes, example:

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

SignUpViewController* viewController = [uiAssembly signUpViewController];

有关此方法的更多信息,请参见以下文章的模块化部分用户指南.

More information on this approach can be found in the modularization section of the user guide.

这篇关于如何使用Typhoon为集成测试注入伪造的,存根的或模拟的依赖项的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆