单元测试和集成测试

来源:互联网 发布:live2d有mac版本的吗 编辑:程序博客网 时间:2024/05/19 06:47

单元测试和集成测试

Unit: 单元测试,保证每一个类能够正常工作
UI: UI测试,也叫做集成测试,从业务层的角度保证各个业务可以正常工作。

0. 单元测试

准则:
保持测试的单一性
无耦合

概念:

在计算机编程中,单元测试(英语:Unit Testing)又称为模块测试, 是针对程序模块的最小单位来进行正确性检验的测试工作。程序单元是应用的最小可测试部件。在过程化编程中,一个单元就是单个程序、函数、过程等;对于面向对象编程,最小单元就是方法,包括基类(超类)、抽象类、或者派生类(子类)中的方法。 – 维基百科

优点:

避免低级错误
减少调试时间
增加可维护性
方便重构代码

缺点:

开发和维护成本高。
不能完全替代人工测试。

单元测试适合范围:

业务变动不频繁
业务属于核心功能

1. XCTest

- (void)setUp {    [super setUp];    //初始化的代码,在测试方法调用之前调用}- (void)tearDown {    // 释放测试用例的资源代码,这个方法会每个测试用例执行后调用    // 如测试踢人接口后,需要在结束时将对应成员拉回群里,以保证下次的单元测试能够正常进行。    [super tearDown];}// 判断这个类是否存在- (void)testStackExist {    XCTAssertNotNil([TestStack class], @"不存在");}// 判断这类是否能创建- (void)testStackCanCreate {    TestStack *stack = [TestStack new];    XCTAssertNotNil(stack, @"不能创建");}- (void)testPushANumberAndGetIt {    TestStack *stack = [TestStack new];    [stack push:2.0];    double topN = [stack pop];    XCTAssertEqual(topN, 2.0, @"怎么不相等呢");//    [stack push:6.0];//    double topN2 = [stack pop];//    XCTAssertEqual(topN2, 2.0, @"怎么不相等呢");}- (void)testPerformanceExample {    // 测试性能例子    [self measureBlock:^{        // 需要测试性能的代码    }];}
  1. 常用断言
 XCTFail(format…) 生成一个失败的测试; XCTAssertNil(arg1, format...) 为空判断,arg1为空时通过,反之不通过; XCTAssertNotNil(arg1, format…) 不为空判断,arg1不为空时通过,反之不通过; XCTAssert(expression, format...) 当expression求值为TRUE时通过; XCTAssertTrue(expression, format...) 当expression求值为TRUE时通过; XCTAssertFalse(expression, format...) 当expression求值为False时通过; XCTAssertEqualObjects(arg1, arg2, format...) 判断相等,[arg1 isEqual: arg2] 值为True时通过,其中一个不为空时,不通过; XCTAssertNotEqualObjects(arg1, arg2, format...) 判断不等,[arg1 isEqual: arg2]值为False时通过, XCTAssertEqual(arg1, arg2, format...) 判断相等(当arg1和arg2是 C语言标量、结构体或联合体时使用,实际测试发现NSString也可以); XCTAssertNotEqual(arg1, arg2, format...) 判断不等(当arg1和arg2是 C语言标量、结构体或联合体时使用); XCTAssertEqualWithAccuracy(arg1, arg2, accuracy, format...) 判断相等,(double或float类型)提供一个误差范围,当在误差范围(+/-accuracy)以内相等时通过测试; XCTAssertNotEqualWithAccuracy(arg1, arg2, accuracy, format...) 判断不等,(double或float类型)提供一个误差范围,当在误差范围以内不等时通过测试; XCTAssertThrows(expression, format...) 异常测试,当expression发生异常时通过;反之不通过;(很变态) XCTAssertThrowsSpecific(expression, specificException, format...) 异常测试,当expression发生specificException异常时通过;反之发生其他异常或不发生异常均不通过; XCTAssertThrowsSpecificNamed(expression, specificException, exception_name, format...) 异常测试,当expression发生具体异常、具体异常名称的异常时通过测试,反之不通过; XCTAssertNoThrow(expression, format...) 异常测试,当expression没有发生异常时通过测试; XCTAssertNoThrowSpecific(expression, specificException, format...) 异常测试,当expression没有发生具体异常、具体异常名称的异常时通过测试,反之不通过; XCTAssertNoThrowSpecificNamed(expression, specificException, exception_name, format...) 异常测试,当expression没有发生具体异常、具体异常名称的异常时通过测试,反之不通过

2. 第三方测试框架

  • OCMock
  • Kiwi 老牌测试框架
  • specta
  • Quick 支持swift

mock 表示一个模拟对象, 它是对现有类的行为一种模拟(或是对现有接口实现的模拟)
stub 追踪方法的调用,在方法调用的时候返回指定的值。
mock 与 stub 最大的区别在于 stub 只是简单的方法替换,而不涉及新的对象,被 stub 的对象可以是业务代码中真正的对象。而 mock 行为本身产生新的(不可能在业务代码中出现的)对象,并遵循类的定义相应某些方法。

3. Kiwi

#import <Kiwi/Kiwi.h>#import "YppNetworkService.h"SPEC_BEGIN(YppNetworkServiceSpec)describe(@"YppNetworkService", ^{    context(@"提审 环境测试: ", ^{        it(@"APP_STORE 应该 等于 1 ", ^{            [[theValue(APP_STORE) should] equal:theValue(1)];        });        it(@"ApiVersion 应该 等于 61 ", ^{            [[kApiVersion should] equal:@"61"];        });        it(@"app version  应该 等于 3.3.9 ", ^{            NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];            NSString *app_Version = [infoDictionary objectForKey:@"CFBundleShortVersionString"];            [[app_Version should] equal:@"3.5.1"];        });    });});SPEC_END

describe : 行为描述(Specs), 描述需要测试的对象内容
context : 描述测试上下文
it 中的是测试的本体,描述了这个测试应该满足的条件, 实际的测试写在it里,是由一个一个的期望(Expectations)来进行描述的,期望相当于传统测试中的断言,要是运行的结果不能匹配期望,则测试失败

it有两个参数:

* 行为描述* 行为的测试代码

三者共同构成了Kiwi测试中的行为描述。

其他关键词:

  • 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

  • 由于有context的存在,以及其可以嵌套的特性,测试的流程控制相比传统测试可以更加精确。我们更容易把before和after的作用区域限制在合适的地方。

在Kiwi中期望都由should或者shouldNot开头,并紧接一个或多个判断的的链式调用,大部分常见的是be或者haveSomeCondition的形式

注意:

  1. 对于 Kiwi 的 stub,需要注意的是它不是永久有效的,在每个 it block 的结尾 stub 都会被清空,超出范围的方法调用将不会被 stub 截取到。
  2. 2.

4. 让你的代码更容易单元测试

测试的准确性和工作量很大程度上依赖于开发人员的代码质量。

通常,为了单元测试的准确性,我们在写函数(方法)的时候会借鉴一些函数式编程的思想。其中最重要的一个思想就是 —- pure function(纯函数)

何为Pure function? 就是如果一个函数的输入一样,那么输出一定一样。

比如,这样的一个函数就不是pure function。因为它依赖于外部变量value的值。

static NSInteger value = 0;- (NSInteger)function_1{    value = value + 1;    return value;}

而这个函数就是pure function,因为给定输入,输出一定一致

- (NSInteger)function:(NSInteger)value{    value = value + 1;    return value;}

如果你写了一个没有参数,或者没有返回值的方法,那么你要小心了,很可能这个方法很难测试。

5. code coverage 测试覆盖率

report -> by group -> coverage

6. 概念

TDD(Test Driven Development) - 测试驱动开发 是保证代码质量的不二法则, 是敏捷开发中的一项核心实践和技术,也是一种设计方法论。TDD的原理是在开发功能代码之前,先编写单元测试用例代码,测试代码确定需要编写什么产品代码。TDD虽是敏捷方法的核心实践,但不只适用于XP(Extreme Programming),同样可以适用于其他开发方法和过程。
TDD的基本思路就是通过测试来推动整个开发的进行,但测试驱动开发并不只是单纯的测试工作,而是把需求分析,设计,质量控制量化的过程。

BDD(Behavior-driven development) - 行为驱动开发。行为驱动开发简单来说就是先定义行为,然后定义测试用例,接着再编写代码。 实践中发现,通常没有那么多时间来先定义行为,不过BDD中的domain-specific language (DSL)能够很好的描述用例的行为。
BDD的框架让测试用例的目的更加明确,测试是否通过更加清晰
BDD的核心是行为。也就是说,需要关注的是一个类提供哪些行为

参考完档:
1. Kiwi 使用 –王巍
2. Kiwi 使用进阶 –王巍

原创粉丝点击