Kiwi -- BDD 模式下的单元测试自动化

2019-07-28  本文已影响0人  红发_KVO

Kiwi -- BDD 模式下的单元测试自动化

首先看到标题里面的BDD,这是什么鬼?这里,我们先来看看目前的不一样的测试思想。

TDD和 BDD

看完上面两种测试思想的差异之后,我想,在我们当前的 iOS 和国内环境下,BBD 测试方法将是我们的首选。而 BDD,不得不介绍一下它-- Kiwi

Kiwi

Kiwi 的 GitHub地址:https://github.com/kiwi-bdd/Kiwi

安装方式

target :YourProjectTests do
    pod 'Kiwi';
end

在这里必须得注意YourProject是你自己的项目名。

Kiwi 的基本语法和结构

在我们开始自己编写 Kiwi语法之前,我们先来看看Kiwi的GitHub提供的示例代码。

describe(@"Team", ^{
    context(@"when newly created", ^{
        it(@"should have a name", ^{
            id team = [Team team];
            [[team.name should] equal:@"Black Hawks"];
        });

        it(@"should have 11 players", ^{
            id team = [Team team];
            [[[team should] have:11] players];
        });
    });
});

我们很容易就可以上下文将其提取程Given...When...Then的三段式自然语言

Given a team,when newly created,it should have a name,and should have 11 players

describe 描述需要测试的对象内容,也即是我们三段式中的 Givencontext描述测试的上下文,也就是这个测试在when进行,最后it中的是测试的本体,描述了这个测试应该满足什么期许(条件),三者共同构成了Kiwi 测试中的行为描述。它们是可以nest的,也就是一个Spec文件中可以包含多个describe(虽然我们很少这么做,一个测试文件应该专注于测试一个类);一个describe可以包含多个context,来描述类在不同情景下的行为;一个context可以包含多个it的测试例。

通过这个示例,我们再来了解一下Kiwi的其它一些行为描述关键字,其中比较重要的包括:

可以看到,由于有context的存在,以及其可以嵌套的特性,测试的流程控制相比传统测试可以更加精确。我们更容易把beforeafter的作用区域限制在合适的地方。
实际的测试写在it里,是由一个一个的期望(Expectations)来进行描述的,期望相当于传统测试中的断言,要是运行的结果不能匹配期望,则测试失败。在Kiwi中期望都由should或者shouldNot开头,并紧接一个或多个判断的的链式调用,大部分常见的是be或者haveSomeCondition的形式。

Kiwi 使用实例

如何利用 Kiwi 来进行单元测试呢!
我们工程中添加了一个Person的类

@interface Person : NSObject
- (CGFloat)everyDayTheBodyPutOnWeight:(CGFloat)weight;
- (CGFloat)everyDayRunForKeepFitLoseWeight:(CGFloat)weight;
@interface Person()
@property (nonatomic, assign) CGFloat totalWeight;
@end
@implementation Person

- (instancetype)init
{
    if (self = [super init]) {
        _totalWeight = 50.0;
    }
    return self;
}
- (CGFloat)everyDayTheBodyPutOnWeight:(CGFloat)weight
{
    return _totalWeight + weight;
}

- (CGFloat)everyDayRunForKeepFitLoseWeight:(CGFloat)weight
{
    return _totalWeight - weight;
}

如何通过 kiwi 编写这个类的单元测试呢?

#import <Kiwi/Kiwi.h>
#import "Person.h"

SPEC_BEGIN(PersonSpec)
describe(@"every one for a day", ^{
    
    context(@"for lose or put on weight", ^{
        
        __block Person *p = nil;
        beforeEach(^{
            p = [Person new];
        });
        afterEach(^{
            p = nil;
        });
        
        it(@"put on weight", ^{
            CGFloat onWeight = [p everyDayTheBodyPutOnWeight:7];
            [[theValue(onWeight) should] equal:57 withDelta:2];
        });
        
        it(@"lose weight", ^{
            CGFloat loseWeight = [p everyDayRunForKeepFitLoseWeight:10];
            [[theValue(loseWeight) should] beLessThanOrEqualTo:theValue(50)];
        });
        
    });
});

SPEC_END

当我们用 command + U 运行这段测试用例的时候,输出如下

- 'every one for a day  when for lose or put on weight, put on weight' [PASSED]
- 'every one for a day  when for lose or put on weight, lose weight' [PASSED]'

来解释下上面的语法中用到的theValue.

Kiwi 为我们提供了一个标量转对象的语法糖,叫做theValue,在做精确比较的时候我们可以直接使用例子中直接与7或者10做比较这样的写法来进行对比。

通过这样一个简单的例子,我们基本能掌握Kiwi的简单语法,以及Kiwi的使用。单元测试尽管入门门槛不高,但是如何用心的,动脑子的去写单元测试,并且可以实现自动化,则是对我们程序员莫大的考验哦。
想要更进阶的使用 kiwi 的话,请看Kiwi 使用进阶 Mock, Stub, 参数捕获和异步测试

总结:

首先,和CocoaPods结合紧密,官方创建Pods后直接支持生成Kiwi的测试项目;
其次,由于其BDD的特性,语法可读性很强;
最后,由于是基于XCTest来开发的,对XCode的支持很好,直接通过XCode进行测试回归或调试即可。

参考文献:

TDD的iOS开发初步以及Kiwi使用入门

iOS开发——TDD、BDD方法以及Kiwi单元测试框架

上一篇 下一篇

猜你喜欢

热点阅读