我想测试这样的课程:
class Foo {
var number: Int = 0
}
在iOS单元测试中,通常的测试用例应为:
class FooTests: XCTestCase {
var foo: Foo!
override func setUp() {
foo = Foo()
}
override func tearDown() {
foo = nil
}
func testAbc() {
print(foo.number)
foo.number = 10
}
func testBCD() {
print(foo.number)
}
}
然后
class FooTests: XCTestCase {
let foo = Foo()
func testAbc() {
print(foo.number)
foo.number = 10
}
func testBCD() {
print(foo.number)
}
}
我看到输出全为0,这意味着当每个启动测试用例foo
似乎都被初始化时。就像使用setUp
和tearDown
一样。
双方都一样吗?
编辑:
感谢@Anton的回答,我什至没有使用setUp
但使用tearDown
进行了测试,然后与同时使用setUp
和tearDown
进行了测试。
var foo: Foo! = Foo()
override func tearDown() {
foo = nil
}
答案 0 :(得分:1)
他们的行为相同但有所不同。要了解差异,可以将其添加到测试类的init和deinit方法中:
class Foo {
var number: Int = 0
init() {
print("Init")
}
deinit {
print("Deinit")
}
}
现在,您将看到在每种情况下,在第一种情况下的init和deinit调用。 因为setUp和tearDown是实例方法,并且在运行测试之前和之后调用。
但是在第二种情况下,init在创建测试套件期间被调用两次。发生这种情况是因为您对foo常量使用了默认的初始化程序。它在测试用例初始化期间调用,该初始化发生在运行任何测试之前。
因此,最好使用第一个选项。因为如果正在测试的实例使用某种全局状态或具有副作用,那么您可能会得到不稳定的测试。它们并行地存在于内存中。
答案 1 :(得分:1)
请注意
var foo: Foo! = Foo()
override func tearDown() {
foo = nil
}
仍然不正确。问题是实例化测试时将创建Foo。所有测试都立即实例化。因此,如果此套件中有5个测试用例,则意味着将有5个FooTests实例,每个实例都有自己的Foo。以及所有运行测试之前。
这可能会引起问题,特别是如果Foo向诸如NotificationCenter之类的共享控制器注册自己的话。
相反,做
private var foo: Foo!
override func setUp() {
super.setUp()
foo = Foo()
}
override func tearDown() {
foo = nil
super.tearDown()
}
这保证了将在运行的测试用例的上下文中创建foo
。
您可以在Most Swift Folks Are Wrong about XCTestCase tearDown…中找到对此的探索。我的新书 iOS Unit Testing by Example: XCTest Tips and Techniques Using Swift 的第二章将对此进行详细介绍。