XCTestCase的setUp方法的目的是什么?

JRG*_*per 38 ios ios7 xctest

每默认模板中的注释XCTestCase有关setUp:

Put setup code here; it will be run once, before the first test case.

但是,XCTestCase.h上述评论中有setUp不同之处:

Setup method called before the invocation of each test method in the class.

为了确认实际行为,我在NSLog内部setUp计算它被调用的次数:

static int count = 0;

- (void)setUp
{
    [super setUp];
    count++;

    NSLog(@"Call Count = %d", count);
}
Run Code Online (Sandbox Code Playgroud)

这导致在setUp每个测试方法之前调用该方法(确认评论XCTestCase.h).

我想使用该setUp方法创建一次测试/模拟对象(例如,设置Core Data测试堆栈).一遍又一遍地创建这些将是处理器密集型的并且可能非常慢.

所以,

1)setUp实际上打算用于什么?当然开发人员不是一遍又一遍地在其中创建对象?

2)如何在一个内创建这些对象一次XCTestCase

Jam*_*ost 86

这里有几点需要讨论:setUp方法的行为和一般的最佳测试实践.

实际上有两种 setUp方法:

+ (void)setUp;
- (void)setUp;
Run Code Online (Sandbox Code Playgroud)

类method(+ (void)setUp)仅在整个测试运行期间运行一次.

实例方法(- (void)setUp)是默认模板中的方法; 它在每次测试之前运行.希望在Xcode的假设未来版本中,此评论将更改为// Put setup code here. This method is called before the invocation of each test method in the class.WINK WINK

因此,通过这两种方法,您描述的两种行为都是可能的.

关于你的评论:

"当然开发人员不是一遍又一遍地在其中创建对象?"

我的答案是"是的,他们通常是".'良好'单元测试的流行首字母缩写是FIRST:

  • 快速
  • 隔离的
  • 重复
  • 自我验证
  • 及时

隔离是讨论的关键:您的测试不应该依赖于其他测试留下的任何先前状态.理想情况下,您应该为每次测试拆除并重新创建内存中的Core Data堆栈,这样您就知道自己是从一个干净的平板开始的.格雷厄姆·李这篇文章中就是一个很好的例子.你想使用内存堆栈,因为a)你可以很容易地扔掉它,而b)它应该非常快,因为它只是在内存中而不是你的磁盘.

如果您因此发现测试运行缓慢(不要过早优化),那么我认为合理的下一步是在您的+ (void)setUp方法中创建堆栈,但每次在您的- (void)setUp方法中创建一个全新的上下文.

  • +1:精彩的回答!是的,考虑一下,*1)测试订单不能保证*(但是通过良好的测试,无论发生什么时候都应该发生)和*2)测试不应该受到其他测试正在做什么的影响*(如你提到,他们"不应该依赖任何先前的测试状态".也很好用`in-memory`堆栈.这就是我要做的. (2认同)

Zeb*_*Zeb 5

我来到这里时遇到了几乎相同的问题:如何setUp 在 Swift 中执行一次。这是解决方案:

override class func setUp() {
    super.setUp()    
    // ...
}

override class func tearDown() {    
    // ...
    super.tearDown()
}
Run Code Online (Sandbox Code Playgroud)

现在我仍在寻找异步 的解决方案setUp

  • 异步设置似乎没有用,因为根据定义,您希望在该类中运行任何测试之前完成设置。 (5认同)