抛出一个问题:TDD 看上去很好,应该用它吗?
这个问题不用着急回答,回答了也不会有对错之分。开发中经常是这样一个流程,新的需求出来后,先经过技术评审会议,确定宏观层面的技术方案、确定各个端的技术实现、使用的技术等,整理出开发文档、会议文档。工期评估后开始编码。事情这么简单吗?前期即使想的再充分、再细致,可能还是存在特殊 case 漏掉的情况,导致技术方案或者是技术实现的改变。如果采用 TDD,那么之前新功能给到后,就要考虑测试用例的设计、编写了测试代码,在测试用例的保证下再去实现功能。如果遇到了技术方案的变更,之前的测试用例要改变、测试代码实现要改变。可能新增的某个 case 导致大部分的测试代码和实现代码都要改变。
如何开展 TDD
新建一个工程,确保 “Include Unit Tests” 选项是选中的状态。
[attach]133678[/attach]
创建后的工程目录如下:
[attach]133679[/attach]
删除 Xcode 创建的测试模版文件 TDDDemoTests.m。
假如我们需要设计一个人类,它具有吃饭的功能,且当他吃完后会说一句“好饱啊”。
那么按照 TDD 我们先设计测试用例。假设有个 Person 类,有个对象方法叫做吃饭,吃完饭后会返回一个“好饱啊”的字符串。那测试用例就是:
[attach]133680[/attach]
实现测试用例代码。创建继承自 Unit Test Case class 的测试类,命名为 工程前缀+测试类名+Test,也就是 TDDPersonTest.m。
[attach]133681[/attach]
因为要测试 Person 类,所以在主工程中创建 Person 类。
因为要测试人类在吃饭后说一句“好饱啊”。所以设想那个类目前只有一个吃饭的方法。于是在 TDDPersonTest.m 中创建一个测试函数 -(void)testReturnStatusStringWhenPersonAte;函数内容如下:
Xcode 下按快捷键 Command + U,跑测试代码发现是失败的。因为我们的 Person 类根本没实现相应的方法。
从 TDD 开发过程可以看到,我们现在是红色的 “Fail” 状态。所以需要去 Person 类中实现功能代码。Person 类如下:
#import "Person.h"
@implementation Person
- (NSString *)eat
{
[NSThread sleepForTimeInterval:1];
return @"好饱啊";;
}
@end
复制代码
再次运行,跑一下测试用例(Command + U 快捷键)。发现测试通过,也就是TDD 开发过程中的绿色 “Success” 状态。
例子比较简单,假如情况需要,可以在 -(void)setUp 方法里面做一些测试的前置准备工作,在 -(void)tearDown 方法里做资源释放的操作。
假如 eat 方法实现的不够漂亮。现在在测试用例的保证下,大胆重构,最后确保所有的 Unit Test case 通过即可。
* @param ... An optional supplementary description of the failure. A literal NSString, optionally with string format specifiers. This parameter can be completely omitted.
*/
#define XCTFail(...) \
_XCTPrimitiveFail(self, __VA_ARGS__)
/*!
* @define XCTAssertNil(expression, ...)
* Generates a failure when ((\a expression) != nil).
* @param expression An expression of id type.
* @param ... An optional supplementary description of the failure. A literal NSString, optionally with string format specifiers. This parameter can be completely omitted.
* Generates a failure when ((\a expression) == nil).
* @param expression An expression of id type.
* @param ... An optional supplementary description of the failure. A literal NSString, optionally with string format specifiers. This parameter can be completely omitted.
* Generates a failure when ((\a expression) == false).
* @param expression An expression of boolean type.
* @param ... An optional supplementary description of the failure. A literal NSString, optionally with string format specifiers. This parameter can be completely omitted.
* Generates a failure when ((\a expression) == false).
* @param expression An expression of boolean type.
* @param ... An optional supplementary description of the failure. A literal NSString, optionally with string format specifiers. This parameter can be completely omitted.
* Generates a failure when ((\a expression) != false).
* @param expression An expression of boolean type.
* @param ... An optional supplementary description of the failure. A literal NSString, optionally with string format specifiers. This parameter can be completely omitted.
* Generates a failure when ((\a expression1) not equal to (\a expression2)).
* @param expression1 An expression of id type.
* @param expression2 An expression of id type.
* @param ... An optional supplementary description of the failure. A literal NSString, optionally with string format specifiers. This parameter can be completely omitted.
* Generates a failure when ((\a expression1) equal to (\a expression2)).
* @param expression1 An expression of id type.
* @param expression2 An expression of id type.
* @param ... An optional supplementary description of the failure. A literal NSString, optionally with string format specifiers. This parameter can be completely omitted.
* Generates a failure when ((\a expression1) != (\a expression2)).
* @param expression1 An expression of C scalar type.
* @param expression2 An expression of C scalar type.
* @param ... An optional supplementary description of the failure. A literal NSString, optionally with string format specifiers. This parameter can be completely omitted.
* Generates a failure when ((\a expression1) == (\a expression2)).
* @param expression1 An expression of C scalar type.
* @param expression2 An expression of C scalar type.
* @param ... An optional supplementary description of the failure. A literal NSString, optionally with string format specifiers. This parameter can be completely omitted.
* Generates a failure when (difference between (\a expression1) and (\a expression2) is > (\a accuracy))).
* @param expression1 An expression of C scalar type.
* @param expression2 An expression of C scalar type.
* @param accuracy An expression of C scalar type describing the maximum difference between \a expression1 and \a expression2 for these values to be considered equal.
* @param ... An optional supplementary description of the failure. A literal NSString, optionally with string format specifiers. This parameter can be completely omitted.
* Generates a failure when (difference between (\a expression1) and (\a expression2) is <= (\a accuracy)).
* @param expression1 An expression of C scalar type.
* @param expression2 An expression of C scalar type.
* @param accuracy An expression of C scalar type describing the maximum difference between \a expression1 and \a expression2 for these values to be considered equal.
* @param ... An optional supplementary description of the failure. A literal NSString, optionally with string format specifiers. This parameter can be completely omitted.
* Generates a failure when ((\a expression1) <= (\a expression2)).
* @param expression1 An expression of C scalar type.
* @param expression2 An expression of C scalar type.
* @param ... An optional supplementary description of the failure. A literal NSString, optionally with string format specifiers. This parameter can be completely omitted.
* Generates a failure when ((\a expression1) < (\a expression2)).
* @param expression1 An expression of C scalar type.
* @param expression2 An expression of C scalar type.
* @param ... An optional supplementary description of the failure. A literal NSString, optionally with string format specifiers. This parameter can be completely omitted.
* Generates a failure when ((\a expression1) >= (\a expression2)).
* @param expression1 An expression of C scalar type.
* @param expression2 An expression of C scalar type.
* @param ... An optional supplementary description of the failure. A literal NSString, optionally with string format specifiers. This parameter can be completely omitted.
* Generates a failure when ((\a expression1) > (\a expression2)).
* @param expression1 An expression of C scalar type.
* @param expression2 An expression of C scalar type.
* @param ... An optional supplementary description of the failure. A literal NSString, optionally with string format specifiers. This parameter can be completely omitted.
* Generates a failure when ((\a expression) does not throw).
* @param expression An expression.
* @param ... An optional supplementary description of the failure. A literal NSString, optionally with string format specifiers. This parameter can be completely omitted.
* Generates a failure when ((\a expression) does not throw \a exception_class).
* @param expression An expression.
* @param exception_class The class of the exception. Must be NSException, or a subclass of NSException.
* @param ... An optional supplementary description of the failure. A literal NSString, optionally with string format specifiers. This parameter can be completely omitted.
* Generates a failure when ((\a expression) does not throw \a exception_class with \a exception_name).
* @param expression An expression.
* @param exception_class The class of the exception. Must be NSException, or a subclass of NSException.
* @param exception_name The name of the exception.
* @param ... An optional supplementary description of the failure. A literal NSString, optionally with string format specifiers. This parameter can be completely omitted.
* Generates a failure when ((\a expression) throws).
* @param expression An expression.
* @param ... An optional supplementary description of the failure. A literal NSString, optionally with string format specifiers. This parameter can be completely omitted.
* Generates a failure when ((\a expression) throws \a exception_class).
* @param expression An expression.
* @param exception_class The class of the exception. Must be NSException, or a subclass of NSException.
* @param ... An optional supplementary description of the failure. A literal NSString, optionally with string format specifiers. This parameter can be completely omitted.
* Generates a failure when ((\a expression) throws \a exception_class with \a exception_name).
* @param expression An expression.
* @param exception_class The class of the exception. Must be NSException, or a subclass of NSException.
* @param exception_name The name of the exception.
* @param ... An optional supplementary description of the failure. A literal NSString, optionally with string format specifiers. This parameter can be completely omitted.