iOS 使用Kiwi测试框架进行单元测试

关于使用XCTest进行单元测试,看这篇参考博客-硬币

demo地址

1.Kiwi简介

Kiwi是一个iOS平台十分好用的行为驱动开发(Behavior Driven Development,以下简称BDD)的测试框架,有着非常漂亮的语法,可以写出结构性强,非常容易读懂的测试。

2.Kiwi相对于XCTest的优势

        --XCTest是基于OCUnit的传统测试框架,在书写性和可读性上都不太好。

        --XCTest测试另外一个问题是难以进行mock或者stub,而这在测试中是非常重要的一部分。

3.Kiwi安装

    1.1--CocoaPos安装(CocoaPos使用-硬币),在Podfile文件中添加如下,UnitTestDemoTests改成自己的测试target

            target 'UnitTestDemoTests'  do
                pod 'Kiwi'

            end

    1.2--如果不使用CocoaPods的话,不使用CocoaPos安装Kiwi

    2.1--安装Xcode Templates模板,下载地址,下载后找到install-templates.sh文件,拖到终端安装,安装遇到问题看这篇

4.创建测试文件

    如果安装了模板的话,直接新建文件,选择

    然后输入测试文件名字,模板会自动加上Spec后缀,这里命名为SimpaleTest,

    这个测试文件中代码如下

    如果您没有安装Kiwi的Template的话,可以直接创建一个普通的Objective-C test case class,然后将内容替换

#import <Kiwi/Kiwi.h>

SPEC_BEGIN(SimpaleTestSpec)

describe(@"SimpaleTest", ^{

});

SPEC_END

5.进行测试

  我们先写一个被测试的类Viewcontroller并添加一个被测试的方法,一个加法运算,代码如下

.h
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController

- (NSInteger)addA:(NSInteger)a andB:(NSInteger)b;

@end

.m
#import "ViewController.h"

@implementation ViewController

- (NSInteger)addA:(NSInteger)a andB:(NSInteger)b
{
    return a+b;
}

@end

在测试文件里引入这个类并添加测试代码如下

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

SPEC_BEGIN(SimpaleTestSpec)

describe(@"SimpaleTest", ^{
    
    //当前scope内部的所有的其他block运行之前调用一次
    beforeAll(^{
    });
    
    //当前scope内部的所有的其他block运行之后调用一次
    afterAll(^{
    });
    
    __block ViewController*vc = nil;
    //在scope内的每个it之前调用一次,对于context的配置代码应该写在这里
    beforeEach(^{
        vc = [ViewController new];
    });
    
    //在scope内的每个it之后调用一次,用于清理测试后的代码
    afterEach(^{
        vc = nil;
    });
    
    //测试代码写在这里
    it(@"test message addA andB", ^{
        [[theValue([vc addA:1 andB:2]) should] equal: theValue(3)];
    });
});

SPEC_END
beforeAll(aBlock) - 当前scope内部的所有的其他block运行之前调用一次
afterAll(aBlock) - 当前scope内部的所有的其他block运行之后调用一次
beforeEach(aBlock) - 在scope内的每个it之前调用一次,对于context的配置代码应该写在这里
afterEach(aBlock) - 在scope内的每个it之后调用一次,用于清理测试后的代码
specify(aBlock) - 可以在里面直接书写不需要描述的测试
pending(aString, aBlock) - 只打印一条log信息,不做测试。这个语句会给出一条警告,可以作为一开始集中书写行为描述时还未实现的测试的提示。
xit(aString, aBlock) - 和pending一样,另一种写法。因为在真正实现时测试时只需要将x删掉就是it,但是pending语意更明确,因此还是推荐pending

一个测试文件建议只测试一个对应的类,一个测试文件建议只有一个describe,一个describe里可以添加多个context,一个context可以包含多个it的测试例,测试代码写在it里,这个例子我们测试vc的一个方法,输入1和2,并断言返回值是3,如果断言成立,则测试通过。

Kiwi中的断言都有should或者shouldNot开头,并紧接一个或者多个判断的链式调用,大部分常见的是be或者haveSomeCondition的形式,完整的期望语句参考这里,

PS:theValue是将标量转换为对象的语法糖,

      theBlock是将一段程序转换为相应行为,转换后可以施加期望判断语句,例如当被测试的函数返回一个异常时,可以用theBlock将异常转换为相应的行文并加上预期,例如

it(@"should raise a exception when pop", ^{
    [[theBlock(^{
        [stack pop];
    }) should] raiseWithName:@"raiseName"];
});

以上内容有理解的可以参考喵神博客,讲的很详细。

6.异步测试    

为了设置异步测试,你必须 使用expectFutureValue 装箱,并且使用 shouldEventually shouldEventuallyBeforeTimingOutAfter来验证.

shouldEventually 默认在判定为失败前等待一秒.

当主语中含有标量时,应该在 expectFutureValue中使用 theValue装箱标量.例如:

[[expectFutureValue(theValue(myBool)) shouldEventually] beYes];

shouldEventuallyBeforeTimingOutAfter()这个block默认值是2秒而不是1秒.

官方例子
context(@"Fetching service data", ^{
        it(@"should receive data within one second", ^{

            __block NSString *fetchedData = nil;
             //发送请求
            [[LRResty client] get:@"http://www.example.com" withBlock:^(LRRestyResponse* r) {
                NSLog(@"That's it! %@", [r asString]);
                fetchedData = [r asString];
            }];

      [[expectFutureValue(fetchedData) shouldEventually] beNonNil];
        });
    });

关于Mock、Stub和参数捕捉的介绍可以看喵神关于Kiwi的进阶使用这个博客也很详细

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值