Skip to content

Latest commit

 

History

History
236 lines (130 loc) · 12.6 KB

03Writing Test Classes and Methods.md

File metadata and controls

236 lines (130 loc) · 12.6 KB

本章由CocoaChina翻译小组成员dada翻译 github地址

#编写测试类与方法 当你使用测试导航面板往项目中添加测试目标时,Xcode 会在测试导航面板里展示出测试类与方法。在测试目标里是包含测试方法的测试类。本章节讲述怎样创建测试类和编写测试方法。

##测试目标,测试包,测试导航 在学习创建测试类前,有必要看看测试导航面板。它对创建和运行测试工作极为重要。

测试导航面板罗列了测试包里的所有组件内容,并在一个层次列表里展示出测试类和测试方法。下面是一个工程的测试导航面板视图,包含了多个测试目标,展示了测试包、测试类以及测试方法的嵌套层级。

测试包可包含多个测试类。你可以使用测试类把测试分到相关的组群中,或者按照功能分,或者按照组织目的分。比如,对于本章中的计算器示例工程,你可以创建BasicFunctionsTests, AdvancedFunctionsTests以及 DisplayTests classes三个类,但他们都属于Mac_Calc_Tests测试包。

一些测试类型可能会共享某些类型的安装和卸载需求,把这些测试整合到类里面会更加合理,这样可以最小化每个测试方法所需编写的代码。

##创建测试类 可以使用加号按钮(+)和测试导航面板中的 New Test Class 命令创建新测试类。

基于你在配置页面键入的测试类名,你添加的每个类都会使得一个名为 TestClassName.m 的文件被添加到项目中。

注意:所有测试类都是XCTest框架XCTestCase类的子类。

尽管Xcode会默认的把测试类添加到为工程测试目标所创建的组中,你还是可以在项目中组织自己选择的文件。当你按下Next按钮,标准的 Xcode 添加文件页面如下所示:

你可以用相同的方法在工程导航面板中添加文件。具体使用方法详见Adding an Existing File or Folder

注意:当你用 Xcode5 及以上版本创建工程时,一个测试目标和相关的测试包都会默认的被创建,名字根据工程名获得。比如创建名为MyApp的项目,则会自动生成名为MyAppTests的测试包,以及一个名为MyAppTests的测试类,关联在MyAppTests.m实例文件中。

##测试类的结构 测试类包含如下的基本结构

#import <XCTest/XCTest.h>
 
@interface MyAppTests : XCTestCase
@end
 
@implementation MyAppTests
 
// setUp and tearDown
- (void)setUp
{
    [super setUp];
    // Put additional setup code here.
}
 
- (void)tearDown
{
    // Put additional teardown code here.
    [super tearDown];
}
 
// test methods
- (void)testXXXX
{
    // setup code
    // test logic and XCTest assertions go here.
    // teardown code
}
@end

测试类用 Objective-C 实现。注意实现里包含了方法,比如 setup 和 teardown 的基本实例方法;这些方法是必须的。如果类中所有的测试方法都需要相同的代码,你可以定制 setUp 和 tearDown 来包含这些代码。你添加的代码在每一个测试方法的之前和之后执行。你可以有选择性的添加定制的设置 (+ (void)setUp) 和卸载 teardown (+ (void)tearDown) 方法,他们在类里所有测试方法的之前和之后执行。

Xcode 执行测试可以明确这些方法的使用,这正是我们接下来的内容要讨论的。

##测试执行的流程 在执行测试的过程中,XCTest 找到所有继承于XCTestCase的类(也就是说所有的测试类),并为每个类运行它的所有测试方法。

对于每个类来说,测试开始于类的 setup 方法的运行。对于每个测试方法来说,一个新的类实例被创建,它的实例 setup 方法就会执行。在跑完了测试方法之后,实例卸载方法。类中这样连续重复执行所有测试方法。在运行的类卸载了最后的测试方法后,Xcode会执行类卸载方法,并开始下一个类。这种序列一直重复直到跑完所有测试类的所有测试方法。

##编写测试方法 你通过编写测试方法把测试写到测试类中,一个测试方法是以 test 开头的测试类的实例方法,没有参数,返回void,比如testColorIsRed.测试方法调用工程中的代码,如果代码没有产生预期的结果,那么会用一系列的断言API报错。比如,一个函数返回值可能与预期值相比不同,或者你的测试方法使用了某个类里不适当的方法都将会抛出异常。“XCTest Assertions”描述了这些情况。

为了使测试方法能够正常访问被测试代码,引入正确的头文件到测试类中很重要。

当 Xcode 运行测试时,它调用的每个测试方法都是独立的。因此每个方法需要准备和清理辅助变量、结构以及与主题API进行交互的对象等。如果类中所有测试方法的代码是相同的,你可以直接把它添加到必需的setUptearDown的实例方法中,详见“Test Class Structure”

下面是个测试方法的模型:

- (void)testColorIsRed {
   ...     // Set up, call test subject API. (Code could be shared in setUp method.)
   ...     // Test logic and values, assertions report pass/fail to testing framework.
   ...     // Tear down. (Code could be shared in tearDown method.
}

这里有一个简单的测试方法例子,检查是否成功地为 SampleCalc 创建了CalcView实例,详见“Quick Start”章节:

- (void) testCalcView {
   // setup
   app = [NSApplication sharedApplication];
   calcViewController = (CalcViewController*)[NSApplication sharedApplication] delegate];
   calcView             = calcViewController.view;
 
   XCTAssertNotNil(calcView, @"Cannot find CalcView instance");
   // no teardown needed
}    

更为深入一点的例子可以查看_Testing Apps and Frameworkssample_工程代码。

##XCTest断言

你的测试方法使用 XCTest 框架提供的断言来呈现 Xcode 显示的测试结果。所有断言都有一个相似的形式:项目比较或逻辑表达式,一个失败结果字符串格式,和插入到字符串格式中的参数。

注意:所有断言的最后一个参数是format...,格式字符串和变量参数列表。XCTest 为所有断言提供了默认的失败结果字符串,可使用参数传递到断言里。format字符串提供了可选的额外的失败自定义描述,就可以进一步选择提供的描述。这个参数是可选的,也可以完全被忽略。

比如,Quick StarttestAddition方法中的断言:

XCTAssertEqualObjects([calcViewController.displayField stringValue], @"10", @"Part 2 failed.");

阅读这段简单明了的语句,是说:“Indicate a failure when a string created from the value of the controller’s display field is not the same as the reference string ‘8’” 。如果断言失败,那么 Xcode 在测试导航面板发出失败信号,然后 Xcode 会在 issues 导航面板、源码编辑器以及其他地方展示失败的描述。下面是源代码编辑器中典型的断言结果:

测试类可以包含多个断言,如果任何断言包含失败报告,那么 Xcode 都发出的测试失败信号。

断言分为五种类型:无条件失败、等价测试、nil测试、Boolean测试以及异常测试。

##用类别区分断言

下面的区域列出了 XCTest 断言。你可以在 Xcode 中使用 Quick Help 查看XCTestAssertions.h来引用来获得更多关于 XCTest 断言的信息。

###无条件失败 XCTFail。生成一个无条件失败

 XCTFail(format...)

###等价测试 XCTAssertEqualObjects。当_expression1_不等于_expression2_时报错(或者一个对象为空,另一个不为空)。

 XCTAssertEqualObjects(expression1, expression2, format...)

XCTAssertNotEqualObjects。当_expression1_等于_expression2_时报错

 XCTAssertNotEqualObjects(expression1, expression2, format...)

XCTAssertEqual。当_expression1_不等于_expression2_时报错,这个测试用于C语言的标量。

 XCTAssertEqual(expression1, expression2, format...)

XCTAssertNotEqual。当_expression1_等于_expression2_时报错,这个测试用于C语言的标量。

 XCTAssertNotEqual(expression1, expression2, format...)

XCTAssertEqualWithAccuracy。当_expression1_和_expression2_之间的差别高于 accuracy 时报错。这种测试适用于 floats 和 doubles 这些标量,两者之间的细微差异导致它们不完全相等,但是对所有的标量都有效。

 XCTAssertEqualWithAccuracy(expression1, expression2, accuracy, format...)

XCTAssertNotEqualWithAccuracy。当_expression1_和_expression2_之间的差别低于 accuracy 时报错。这种测试适用于 floats 和 doubles 这些标量,两者之间的细微差异导致它们不完全相等,但是对所有的标量都有效。

 XCTAssertNotEqualWithAccuracy(expression1, expression2, accuracy, format...)

###Nil(空)测试

XCTAssertNil。当_expression_参数非nil时报错。

XCTAssertNil(expression, format...)

XCTAssertNotNil。当_expression_参数为nil时报错。

XCTAssertNotNil(expression, format...)

###布尔测试

XCTAssertTrue。当_expression_计算结果为_false_时报错。

XCTAssertTrue(expression, format...)

XCTAssert。当_expression_计算结果为_false_时报错,与_XCTAssertTrue_同义。

 XCTAssert(expression, format...)

XCTAssertFalse。当_expression_计算结果为_true_时报错。

 XCTAssertFalse(expression, format...)

###异常测试

XCTAssertThrows。当_expression_不抛出异常时报错误。

 XCTAssertThrows(expression, format...)

XCTAssertThrowsSpecific。当_expression_针对指定类不抛出异常时报错。

 XCTAssertThrowsSpecific(expression, exception_class, format...)

XCTAssertThrowsSpecificNamed。当_expression_针对特定类和特定名字不抛出异常时报错。对于AppKit框架或Foundation框架非常有用,抛出带有特定名字的NSException(NSInvalidArgumentException等等)。

XCTAssertThrowsSpecificNamed(expression, exception_class, exception_name, format...)

XCTAssertNoThrow。当_expression_抛出异常时报错。

 XCTAssertNoThrow(expression, format...)

XCTAssertNoThrowSpecific。当_expression_针对指定类抛出异常时报错。任意其他异常都可以;也就是说它不会报错。

XCTAssertNoThrowSpecific(expression, exception_class, format...)

XCTAssertNoThrowSpecificNamed。当_expression_针对特定类和特定名字抛出异常时报错。对于 AppKit 框架或 Foundation 框架非常有用,抛出带有特定名字的NSException(NSInvalidArgumentException等等)。

 XCTAssertNoThrowSpecificNamed(expression, exception_class, exception_name, format...)