我必须使用拆解和设置进行UnitTest

时间:2019-05-06 12:00:36

标签: ios swift unit-testing xctestcase

我想测试这样的课程:

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似乎都被初始化时。就像使用setUptearDown一样。

双方都一样吗?

编辑: 感谢@Anton的回答,我什至没有使用setUp但使用tearDown进行了测试,然后与同时使用setUptearDown进行了测试。

    var foo: Foo! = Foo()

    override func tearDown() {
        foo = nil
    }

2 个答案:

答案 0 :(得分:1)

他们的行为相同但有所不同。要了解差异,可以将其添加到测试类的init和deinit方法中:

class Foo {
    var number: Int = 0

    init() {
        print("Init")
    }

    deinit {
        print("Deinit")
    }
}

现在,您将看到在每种情况下,在第一种情况下的init和deinit调用。 因为setUp和tearDown是实例方法,并且在运行测试之前和之后调用。

但是在第二种情况下,init在创建测试套件期间被调用两次。发生这种情况是因为您对foo常量使用了默认的初始化程序。它在测试用例初始化期间调用,该初始化发生在运行任何测试之前。

因此,最好使用第一个选项。因为如果正在测试的实例使用某种全局状态或具有副作用,那么您可能会得到不稳定的测试。它们并行地存在于内存中。

Diagram

答案 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 的第二章将对此进行详细介绍。