相关概念和用法:
  Stub:
  简单的方法替换,stub一个对象的指定方法后,可以该方法返回任何事先规定好的值。
  用处:对创建麻烦、需要大量配置才能使用、方法的返回结果不固定的类或对象,直接stub指定方法,让方法返回固定值,以使测试继续下去。
    context(@"when select count of termStudyInfo", ^{
       
        beforeEach(^{
        // stub之后任何地方调用[EduTermStudyInfo countOfTermStudyInfoWithLearnerId:],返回值均为3,
        // 而真正的[EduTermStudyInfo countOfTermStudyInfoWithLearnerId:]方法将不会得到调用
           [EduTermStudyInfo stub:@selector(countOfTermStudyInfoWithLearnerId:) andReturn:theValue(3)];
        });
       
        it(@"the count should always be 3", ^{
            [[theValue([EduTermStudyInfo countOfTermStudyInfoWithLearnerId:110]) should] equal:theValue(3)];
        });
    });
  注意:每条测试用例(it)的结尾,stub都会被清空。
  Mock:
  对创建新的对象代价较高或流程复杂的类,直接调用mock方法可创建一个模拟的该类对象(mock对象),这个对象可调用该类的任意方法。
// 调用nullMock创建了一个虚拟的XXSectionDataSource对象,可接收XXSectionDataSource类的任何消息,但不做实际的响应
XXSectionDataSource *mockLiveSection = [XXSectionDataSource nullMock];
// 想要让[mockLiveSection viewType]总是返回XXViewTypeLive,则需要stub该mock对象的viewType方法
    [mockLiveSection stub:@selector(viewType) andReturn:theValue(XXViewTypeLive)];
   
    // 如果不使用nullMock而是使用了mock方法来创建mock对象,则向该mock对象发送没有stub过的消息时,会crash
    XXCellDataSource *mockCell = [XXCellDataSource nullMock];
    [mockCell stub:@selector(viewType) andReturn:theValue(XXViewTypeLive)];
    [mockLiveSection stub:@selector(cellDataSources) andReturn:@[mockCell, mockCell]];
  异步测试:
  对于网络请求等异步操作进行测试时,判断测试结果是否满足期望,需要使用expectFutureValue+shouldEventually 替换同步测试的should。
  expectFutureValue+shouldEventually出现时,会block该线程长1s的时间,直到期望结果得到满足表示测试通过,或者超时表示测试失败。
  具体原理可参考:https://github.com/kiwi-bdd/Kiwi/issues/532
describe(@"XXViewModel", ^{

    context(@"when request lern data", ^{
        __block XXViewModel *viewModel = nil;
        __block BOOL isExecuteSuccess = NO;
       
        beforeEach(^{
            viewModel = [[XXViewModel alloc] init];
            [viewModel requestLearnData:^{
                isExecuteSuccess = YES;
            } failure:nil target:self];
        });

        it(@"should eventually call successBlock", ^{
            //此处为异步测试判断网络请求是否成功
            [[expectFutureValue(theValue(isExecuteSuccess)) shouldEventually] beYes];
        });
});
  OHHTTPStubs框架
  基于NSURLProtocol实现的网络情况stub框架。stub指定的网络请求后,可自定义网络请求返回的内容,相当于Charles的local map功能。
  作用:固定网络请求返回内容,方便依据请求返回做相应功能的测试。具体后端返回的正确性测试应该交由专门的API测试进行。
  用法:一般在beforeEach内进行如下stub:
// 所有url中包含learn/v1的网球请求,均返回learn_v1.json文件中的内容
[OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest * _Nonnull request) {
        return [request.URL.absoluteString containsString:@"learn/v1"];
    } withStubResponse:^OHHTTPStubsResponse * _Nonnull(NSURLRequest * _Nonnull request) {
        NSString *filePath = OHPathForFile(@"learn_v1.json", self.class);
        NSData *data = [NSData dataWithContentsOfFile:filePath];
        return [OHHTTPStubsResponse responseWithData:data statusCode:kK12TestHTTPSuccessCode headers:nil];
        // 模拟请求失败,返回一个NSError
        //return [OHHTTPStubsResponse responseWithError:[NSError errorWithDomain:@"kK12TestSystemErrorDomain" code:-1 userInfo:nil]];
    }];
  问题记录:
  测试启动时Kiwi库报EXC_BAD_ACCESS。解决:修改Kiwi为master新版本:https://github.com/kiwi-bdd/Kiwi/pull/649
  测试启动时宏或第三方库头文件报错。解决:pch文件没有链接
  在RACBacktrace的RACBacktraceBlock,debug时经常EXC_BAD_ACCESS。解决:升级ReactiveCocoa版本。