iOS单元测试(作用及入门)

来源:互联网 发布:给json对象添加属性 编辑:程序博客网 时间:2024/06/16 17:17
  • 单元测试简介
  • 单元测试的用途及作用
  • 用简单的样例说明单元测试
  • 集成单元测试的一些注意事项

单元测试简介

看到文章标题的时候,你也许会问,测试不是测试妹子干的事吗?的确,测试妹子能帮助我们测试出软件的很多问题(不符合业务的问题),但是代码的测试还得靠我们自己啊。团队Leader在开会时一直强调要打造一支不依靠测试团队的团队,因此,代码自测也变成了一个项目重要的一环。是的,今天我要聊的就是我们程序员对自己代码的测试,而不是测试妹子的测试。在iOS开发中我们用单元测试来保证我们的代码可靠性,什么是单元测试,请看在维基百科上的解释:

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

单元测试的作用

要清楚单元测试的作用,肯定首先我们要了解单元测试里面到底有些什么。

OCUnit其实就是苹果自带的测试框架,我们主要讲的就是这个。
GHUnit是一个可视化的测试框架。(有了它,你可以点击APP来决定测试哪个方法,并且可以点击查看测试结果等。)
OCMock就是模拟某个方法或者属性的返回值。你可能会疑惑为什么要这样做?使用模型生成的模型对象,再传进去不就可以了?答案是可以的,但是有特殊的情况。比如你测试的是方法A,方法A里面调用到了方法B,而且方法B是有参数传入,但又不是方法A所提供。这时候,你可以使用OCMock来模拟方法B返回的值。(在不影响测试的情况下,就可以这样去模拟。)除了这些,在没有网络的情况下,也可以通过OCMock模拟返回的数据。
UITests就是通过代码化来实现自动点击界面,输入文字等功能。靠人工操作的方式来覆盖所有测试用例是非常困难的,尤其是加入新功能以后,旧的功能也要重新测试一遍,这导致了测试需要花非常多的时间来进行回归测试,这里产生了大量重复的工作,而这些重复的工作有些是可以自动完成的,这时候UITests就可以帮助解决这个问题了。扯淡这么半天,就是为了说明单元测试能节约我们的时间,提高开发效率,对于项目越大的效果越明显。

当然也有一些高级的作用,比如自动发布、自动测试(特别在一些大的项目,以防止程序被误改或引起新的问题)。

用简单的样例说明单元测试

XCTest
这里写图片描述
如果你的项目已经建立了,你可以通过Target的方式添加,如下图:

这里写图片描述

在test下选择你项目没有的便可:

这里写图片描述

在这2个文件夹目录下分别都有2个文件,一个.m文件和一个plist文件。并且.m文件有4个方法,如下图:

这里写图片描述

项目名+Test的.m文件里面默认有4个方法,这个文件里面主要做一些逻辑的测试。项目名+UITest的.m文件里默认有3个方法。这个文件里面主要做一些UI的测试。说了这么半天,该如何写单元测试呢?在讲解如何写测试方法前,先说说默认的方法是干什么的吧!

//TestDemoTest.m- (void)setUp {    [super setUp];    //每个test方法执行前调用,在这个测试用例里进行一些通用的初始化工作    // Put setup code here. This method is called before the invocation of each test method in the class.}- (void)tearDown {    // Put teardown code here. This method is called after the invocation of each test method in the class.    [super tearDown];    //每个test方法执行后调用}- (void)testExample {    //测试方法样例    // This is an example of a functional test case.    // Use XCTAssert and related functions to verify your tests produce the correct results.}- (void)testPerformanceExample {    //这个方法主要是做性能测试的,所谓性能测试,主要就是评估一段代码的运行时间。该方法就是性能测试方法的样例。    // This is an example of a performance test case.    [self measureBlock:^{        // Put the code you want to measure the time of here.    }];}

测试用例方法非常简单,从testExample这个方法我们大概知道怎么写了吧!方法名只需要以test开头,是的,就是这么简单。现在我们模拟登录这个功能来写一个登录模块的测试用例吧,在User这个模型类里面一个方法叫isChinese的,是用来判断字符串里面是否有中文的。

#import <Foundation/Foundation.h>@interface User : NSObject@property (nonatomic, copy) NSString *userName;@property (nonatomic, copy) NSString *passWord;/** *  判断字符串中是否有中文 * *  @param string <#string description#> * *  @return <#return value description#> */- (BOOL)isChinese:(NSString *)string;@end

现在我们通过Xcode的File->New->File->Source选择Unit Test Case Class来新建一个UserTests,注意要继承XCTestCase类。

这里写图片描述

接下来我们为User类写一个测试isChinese方法的测试方法,叫做testIsChinese,测试用例具体如下:

这里写图片描述

这样,你只要点击测试方法旁边的那个菱形的按钮就可以运行该测试方法啦!通过测试会变成绿色的对勾,失败会变成红色的叉叉。到这里测试用例你就会写了。也许你会在意那些断言,这样的断言有18个,如下:

XCTFail(format…)  //生成一个失败的测试;XCTAssertNil(a1, format...)  //为空判断,a1为空时通过,反之不通过;XCTAssertNotNil(a1, format…) //不为空判断,a1不为空时通过,反之不通过;XCTAssert(expression, format...) //当expression求值为TRUE时通过;XCTAssertTrue(expression, format...) //当expression求值为TRUE时通过;XCTAssertFalse(expression, format...)  //当expression求值为False时通过;XCTAssertEqualObjects(a1, a2, format...)  //判断相等,[a1 isEqual:a2]值为TRUE时通过,其中一个不为空时,不通过;XCTAssertNotEqualObjects(a1, a2, format...)  //判断不等,[a1 isEqual:a2]值为False时通过;XCTAssertEqual(a1, a2, format...)  //判断相等(当a1和a2是 C语言标量、结构体或联合体时使用,实际测试发现NSString也可以);XCTAssertNotEqual(a1, a2, format...)  //判断不等(当a1和a2是 C语言标量、结构体或联合体时使用);XCTAssertEqualWithAccuracy(a1, a2, accuracy, format...)  //判断相等,(double或float类型)提供一个误差范围,当在误差范围(+/-accuracy)以内相等时通过测试;XCTAssertNotEqualWithAccuracy(a1, a2, 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没有发生具体异常、具体异常名称的异常时通过测试,反之不通过

UI测试
用代码写UI测试比较麻烦,但是苹果在Xcode中为我们提供了录制的功能。录制是怎么一回事呢?当你打开时这个功能时,测试代码会随着你在设备或模拟器上操作自动创建。这么一来就省事多了。现在,我们在TestDemoUITests.m文件中写一个方法testLogin作为测试登录流程操作的UI测试方法。然后把光标放在方法体内,然后点击红色的那个录制按钮,如下:

这里写图片描述

当你点击了录制后,程序就会自动启动,这时候你在程序的所有操作都会生成想用的代码在你所选择的方法体内。

接下来我们看看里面输出的代码:

//XCUIApplication 这是应用的代理,他能够把你的应用启动起来,并且每次都在一个新进程中。XCUIApplication *app = [[XCUIApplication alloc] init];//XCUIElement 这是 UI 元素的代理。元素都有类型和唯一标识。可以结合使用来找到元素在哪里,如当前界面上的一个输入框XCUIElement *usernameTextField = app.textFields[@"username:"];[usernameTextField tap];[usernameTextField typeText:@"the"];XCUIElement *passwordTextField = app.textFields[@"password:"];[passwordTextField tap];[passwordTextField tap];[passwordTextField typeText:@"12345"];[[[[[[[app childrenMatchingType:XCUIElementTypeWindow] elementBoundByIndex:0] childrenMatchingType:XCUIElementTypeOther].element childrenMatchingType:XCUIElementTypeOther].element childrenMatchingType:XCUIElementTypeOther].element childrenMatchingType:XCUIElementTypeOther].element tap];[app.buttons[@"login"] tap];

得到这些代码后我们可以对它们进行一些我们需要的处理。在这里就不多啰嗦啦。
如果你想一次跑完所有的测试方法,快捷键cmd+u即可。

集成单元测试的一些注意事项

单元测试 注意事项:

1创建项目时记得勾选include Unit Tests,建议include UI Tests也一起选上。
2添加测试文件
在单元测试项目下,新建文件,选择source下的Unit Test Case Class
tips:如果几个test case都有一些共同的数据或逻辑,可以自己新建一个test case的基类,然后每个分别继承
3项目中用了cocoapods的同学假如想测试第三方的类尤其要注意啦!
由于unit tests是个单独的项目,所以一些项目配置必须重新配置一遍


1 0