FactoryGentleman 1.2.3

FactoryGentleman 1.2.3

测试已测试
Lang语言 Obj-CObjective C
许可证 MIT
发布最后发布2015年10月

Michael England维护。



  • Michael England和Slavko Krucaj

这是一个简单的库,用于帮助定义用于测试iOS/Mac应用程序的模型工厂。大量基于Ruby的FactoryGirl

问题

我们对类SomeClass进行测试,需要一个Data Value Object User的实例。该类只使用username属性。

在测试中,我们必须生成一个有效的User对象,尽管我们几乎不关心它的所有属性。

SpecBegin(SomeClass)
    __block SomeClass *subject;

    before(^{
        User *user = [[User alloc] init];
        user.firstName = @"Bill";
        user.lastName = @"Smith";
        user.friendCount = 7;
        user.title = @"Mr";
        user.maidenName = @"Bloggs";
        subject = [[SomeClass alloc] initWithUser:user];
    });

    it(@"is valid", ^{
        expect([subject isValid]).to.beTruthy();
    });
});

这种设置代码开始主导甚至是最简单的测试,随着我们开始编写更多需要User的测试,我们最终编写了ModelFixtures类来简化代码。

SpecBegin(SomeClass)
    __block SomeClass *subject;

    before(^{
        User *user = [ModelFixtures user];
        subject = [[SomeClass alloc] initWithUser:user];
    });

    it(@"is valid", ^{
        expect([subject isValid]).to.beTruthy();
    });
});

这可以暂时解决,但后来我们意识到我们需要为不同的测试创建多个略有不同的测试用例。因此,ModelFixtures类到处都是附加方法来帮助完成这项工作

@interface ModelFixtures : NSObject
+ (User *)user;
+ (User *)userWithFirstName:(NSString *)firstName;
+ (User *)userWithFirstName:(NSString *)firstName
                   lastName:(NSString *)lastName;
+ (User *)userWithFirstName:(NSString *)firstName
                   lastName:(NSString *)lastName
                 maidenName:(NSString *)maidenName;
@end

介绍FactoryGentleman

使用FactoryGentleman,您在一个文件中定义对象的基字段,然后构建对象,同时也可以覆盖所需的任何字段。

创建一个工厂

创建一个包含工厂定义的实现文件 (*.m)

#import <FactoryGentleman/FactoryGentleman.h>

#import "User.h"

FGFactoryBegin(User)
    builder[@"firstName"] = @"Bob";
    builder[@"lastName"] = @"Bradley";
    [builder field:@"friendCount" integerValue:10];
    builder[@"title"] = @"Mr";
    builder[@"maidenName"] = @"Macallister";
FGFactoryEnd

在测试中使用工厂

#import <FactoryGentleman/FactoryGentleman.h>

#import "User.h"

SpecBegin(User)
    __block User *subject;

    before(^{
        subject = FGBuild(User.class);
    });

    it(@"is valid", ^{
        expect([subject isValid]).to.beTruthy();
    });
});

覆盖字段

构建对象时,您可以传递构建器块或传递值字典来覆盖字段

#import <FactoryGentleman/FactoryGentleman.h>

#import "User.h"

SpecBegin(User)
    __block User *subject;

    context(@"when user has no first name", ^{
        before(^{
            subject = FGBuildWith(User.class, ^(FGDefinitionBuilder *builder) {
                [builder nilField:@"firstName"];
            });
        });

        it(@"is NOT valid", ^{
            expect([subject isValid]).to.beFalsy();
        });
    });
});

或通过传递一个值字典

#import <FactoryGentleman/FactoryGentleman.h>

#import "User.h"

SpecBegin(User)
    __block User *subject;

    context(@"when user has no first name", ^{
        before(^{
            subject = FGBuildWith(User.class, @{ @"firstName" : @"" });
        });

        it(@"is NOT valid", ^{
            expect([subject isValid]).to.beFalsy();
        });
    });
});

复杂和序列化字段

您可以使用块定义具有一些更复杂状态相关值的字段

#import <FactoryGentleman/FactoryGentleman.h>

#import "User.h"

FGFactoryBegin(User)
    __block int currentId = 0;
    [builder field:@"resourceId" by:^{
        return @(++currentId);
    }];
    builder[@"firstName"] = @"Bob";
    builder[@"lastName"] = @"Bradley";
    [builder field:@"friendCount" integerValue:10];
    builder[@"title"] = @"Mr";
    builder[@"maidenName"] = @"Macallister";
FGFactoryEnd

不可变属性

您可以通过列出初始化器选择符和所需的字段名称来定义具有不可变(即只读)属性的对象

#import <FactoryGentleman/FactoryGentleman.h>

#import "User.h"

FGFactoryBegin(User)
    builder[@"firstName"] = @"Bob";
    builder[@"lastName"] = @"Bradley";
    [builder field:@"friendCount" integerValue:10];
    builder[@"title"] = @"Mr";
    builder[@"maidenName"] = @"Macallister";
    [builder initWith:@selector(initWithFirstName:lastName:) fieldNames:@[ @"firstName", @"lastName" ]];
FGFactoryEnd

关联对象

您可以通过提供所需的工厂名称来定义关联对象(具有工厂定义的对象)

#import <FactoryGentleman/FactoryGentleman.h>

#import "User.h"

FGFactoryBegin(User)
    builder[@"firstName"] = @"Bob";
    builder[@"lastName"] = @"Bradley";
    builder[@"friendCount"] = @10;
    builder[@"title"] = @"Mr";
    builder[@"maidenName"] = @"Macallister";
    [builder field:@"address" assoc:Address.class];
FGFactoryEnd

属性

对于具有不同属性的对象,您可以在基本定义中定义它们

#import <FactoryGentleman/FactoryGentleman.h>

#import "User.h"

FGFactoryBegin(User)
    builder[@"firstName"] = @"Bob";
    builder[@"lastName"] = @"Bradley";
    builder[@"friendCount"] = @10;
    builder[@"title"] = @"Mr";
    builder[@"maidenName"] = @"Macallister";
    [builder field:@"address" assoc:Address.class];

    traitDefiners[@"homeless"] = ^(FGDefinitionBuilder *homelessBuilder) {
        [homelessBuilder nilField:@"address"];
    };
FGFactoryEnd

然后可以使用相应的构建宏来使用这些属性

subject = FGBuildTrait(User.class, @"homeless");
subject = FGBuildTraitWith(User.class, @"homeless", ^(FGDefinitionBuilder *builder) {
    builder[@"firstName"] = @"Brian";
});

以及关联定义

[builder field:@"user" assoc:User.class trait:@"homeless"];

只读属性

您可以定义只读属性(非原始)的值,尽管这个功能默认不可用。为了设置它们,您必须在您的头文件中定义FG_ALLOW_READONLY

如何安装

pod "FactoryGentleman"添加到您的Podfile

作者

许可证

FactoryGentleman在MIT许可证下提供。有关更多信息,请参阅LICENSE文件。