【问题标题】:UnitTest should I have to use teardown and setupUnitTest 我应该使用拆卸和设置吗
【发布时间】:2019-05-06 12:00:35
【问题描述】:

我想测试这样一个类:

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
    }

【问题讨论】:

标签: ios swift unit-testing xctestcase


【解决方案1】:

注意

var foo: Foo! = Foo()

override func tearDown() {
    foo = nil
}

仍然不正确。问题是 Foo 将在测试实例化时创建。所有测试都立即实例化。因此,如果该套件中有 5 个测试用例,则意味着将有 5 个 FooTest 实例,每个实例都有自己的 Foo。在运行任何测试之前。

这可能会导致问题,特别是如果 Foo 向共享控制器(如 NotificationCenter)注册自身。

相反,做

private var foo: Foo!

override func setUp() {
    super.setUp()
    foo = Foo()
}

override func tearDown() {
    foo = nil
    super.tearDown()
}

这保证foo 将在正在运行的测试用例的上下文中创建。

【讨论】:

  • " 在运行任何测试之前。"你的意思是有 5 个实例吗 1 在键入 5 个测试用例之后 2. 在单击 FooTests 的测试按钮之后(运行所有测试用例) 3. 单击 5 个测试用例中的任何一个来运行测试。 (即使点击一个测试用例,已经有 5 个实例了?)谢谢!
  • 是的。即使您“运行单个测试”,我也很确定它会先实例化每个测试,然后运行您指定的测试。
【解决方案2】:

他们的行为相似但有区别。要了解差异,您可以添加到测试类的 init 和 deinit 方法中:

class Foo {
    var number: Int = 0

    init() {
        print("Init")
    }

    deinit {
        print("Deinit")
    }
}

现在您将看到在第一个案例中 init 和 deinit 在每个测试中调用。 因为 setUp 和 tearDown 是实例方法,在运行测试之前和之后调用。

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

所以,最好使用第一个选项。因为如果被测试的实例使用一些全局状态或有副作用,那么你可能会得到不稳定的测试。它们并行存在于内存中。

【讨论】:

  • 如果这样number应该在testBCD中改为10,对吧?
  • 没有。因为 XCTest 为每个测试用例创建了两个测试类的实例。因此,您在每次测试时都使用 Foo 实例的副本。
  • 嘿@Anton,我知道了。 Acutally 相同的功能,只是没有tearDown,然后在完成每个测试用例时发布。谢谢!
  • 我什至在没有setUptearDown 的情况下进行了测试,initdeinit 都被调用了两次。 :)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-13
  • 1970-01-01
  • 1970-01-01
  • 2014-11-27
  • 2012-04-09
  • 2015-10-05
相关资源
最近更新 更多