关闭

TDD的iOS开发初步以及Kiwi使用入门

发表于:2014-2-24 11:06

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:OneV\\\'s Den    来源:51Testing软件测试网采编

  可以看到,VVStackTests是XCTestCase的子类,而XCTestCase正是XCTest测试框架中的测试用例类。XCTest在进行测试时将会寻找测试target中的所有XCTestCase子类,并运行其中以test开头的所有实例方法。在这里,默认实现的-testExample将被执行,而在这个方法里,Xcode默认写了一个XCTFail的断言,来强制这个测试失败,用以提醒我们测试还没有实现。所谓断言,就是判断输入的条件是否满足。如果不满足,则抛出错误并输出预先规定的字符串作为提示。在这个Fail的断言一定会失败,并提示没有实现该测试。另外,默认还有两个方法-setUp和-tearDown,正如它们的注释里所述,这两个方法会分别在每个测试开始和结束的时候被调用。我们现在正要开始编写我们的测试,所以先将原来的-testExample删除掉。现在再使用?U来进行测试,应该可以顺利通过了(因为我们已经没有任何测试了)。
  接下来让我们想想要做什么吧。我们要实现一个简单的栈数据结构,那么当然会有一个类来代表这种数据结构,在这个工程中我打算就叫它VVStack。按照常规,我们可以新建一个Cocoa Touch类,继承NSObject并且开始实现了。但是别忘了,我们现在在TDD,我们需要先写测试!那么首先测试的目标是什么呢?没错,是测试这个VVStack类是否存在,以及是否能够初始化。有了这个目标,我们就可以动手开始编写测试了。在文件开头加上#import "VVStack.h",然后在VVStackTests.m的@end前面加上如下代码:
- (void)testStackExist {
XCTAssertNotNil([VVStack class], @"VVStack class should exist.");
}
- (void)testStackObjectCanBeCreated {
VVStack *stack = [VVStack new];
XCTAssertNotNil(stack, @"VVStack object can be created.");
}
  当然是不可能通过测试的,而且甚至连编译都无法完成,因为我们现在根本没有一个叫做VVStack的类。最简单的让测试通过的方法就是在产品代码中添加VVStack类。新建一个Cocoa Touch的Objective-C class,取名VVStack,作为NSObject的子类。注意在添加的时候,应该只将其加入产品的target中:
  
  添加类的时候注意选择合适的target
  由于VVStack是NSObject的子类,所以上面的两个断言应该都能通过。这时候再运行测试,成功变绿。接下来我们开始考虑这个类的功能:栈的话肯定需要能够push,并且push后的栈顶元素应该就是刚才所push进去的元素。那么建立一个push方法的测试吧,在刚才添加的代码之下继续写:
- (void)testPushANumberAndGetIt {
VVStack *stack = [VVStack new];
[stack push:2.3];
double topNumber = [stack top];
XCTAssertEqual(topNumber, 2.3, @"VVStack should can be pushed and has that top value.");
}
  因为我们还没有实现-push:和-top方法,所以测试毫无疑问地失败了(在ARC环境中直接无法编译)。为了使测试立即通过我们首先需要在VVStack.h中声明这两个方法,然后在.m的实现文件中进行实现。令测试通过的最简单的实现是一个空的push方法以及直接返回2.3这个数:
//VVStack.h
@interface VVStack : NSObject
- (void)push:(double)num;
- (double)top;
@end
//VVStack.m
@implementation VVStack
- (void)push:(double)num {
}
- (double)top {
return 2.3;
}
@end
  再次运行测试,我们顺利回到了绿灯状态。也许你很快就会说,这算哪门子实现啊,如果再增加一组测试例,比如push一个4.6,然后检查top,不就失败了么?我们难道不应该直接实现一个真正的合理的实现么?对此的回答是,在实际开发中,我们肯定不会以这样的步伐来处理像例子中这样类似的简单问题,而是会直接跳过一些error-try的步骤,实现一个比较完整的方案。但是在更多的时候,我们所关心和需要实现的目标并不是这样容易。特别是在对TDD还不熟悉的时候,我们有必要放慢节奏和动作,将整个开发理念进行充分实践,这样才有可能在之后更复杂的案例中正确使用。于是我们发扬不怕繁杂,精益求精的精神,在刚才的测试例上增加一个测试,回到VVStackTests.m中,在刚才的测试方法中加上:
  - (void)testPushANumberAndGetIt {
  //...
  [stack push:4.6];
  topNumber = [stack top];
  XCTAssertEqual(topNumber, 4.6, @"Top value of VVStack should be the last num pushed into it");
  }
  很好,这下子我们回到了红灯状态,这正是我们所期望的,现在是时候来考虑实现这个栈了。这个实现过于简单,也有非常多的思路,其中一种是使用一个NSMutableArray来存储数据,然后在top方法里返回最后加入的数据。修改VVStack.m,加入数组,更改实现:
//VVStack.m
@interface VVStack()
@property (nonatomic, strong) NSMutableArray *numbers;
@end
@implementation VVStack
- (id)init {
if (self = [super init]) {
_numbers = [NSMutableArray new];
}
return self;
}
- (void)push:(double)num {
[self.numbers addObject:@(num)];
}
- (double)top {
return [[self.numbers lastObject] doubleValue];
}
@end
  测试通过,注意到在-testStackObjectCanBeCreated和testPushANumberAndGetIt两个测试中都生成了一个VVStack对象。在这个测试文件中基本每个测试都会需要初始化对象,因此我们可以考虑在测试文件中添加一个VVStack的实例成员,并将测试中的初始化代码移到-setUp中,并在-tearDown中释放。
  接下来我们可以模仿继续实现pop等栈的方法。鉴于篇幅这里不再继续详细实现,大家可以自己动手试试看。记住先实现测试,然后再实现产品代码。一开始您可能会觉得这很无聊,效率低下,但是请记住这是起步练习不可缺少的一部分,而且在我们的例子中其实一切都是以“慢动作”在进行的。相信在经过实践和使用后,您将会逐渐掌握自己的节奏和重点测试。关于使用XCTest到这里为止的代码,可以在github上找到。
53/5<12345>
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号