【问题标题】:Shared XCTest unit tests for different implementations of interface针对不同接口实现的共享 XCTest 单元测试
【发布时间】:2016-01-21 16:07:54
【问题描述】:

我有两个或多个接口(协议)的实现:

protocol Interface {
    func methodOne()
    func methodTwo()
}

我想测试每个实现,我不想重复代码。我有几个选择,但没有一个让我满意。

第一个是为ImplementationA 创建测试用例并将其子类化以获取ImplementationB 的测试用例:

class ImplementationATests: XCTestCase {

    var implToTest: Interface!

    override func setUp() {
        super.setUp()
        implToTest = ImplementationA()
    }

    func testMethodOne() {
        ...
    }

    func testMethodTwo() {
        ...
    }
}


class ImplementationBTests: ImplementationATests {

    override func setUp() {
        super.setUp()
        implToTest = ImplementationB()
    }
}

这种方法的一个缺点是我不能进行仅适用于ImplementationA 的测试。 (例如,测试特定于该实现的一些辅助方法)

我想出的第二个选项是为测试用例创建共享子类:

class InterfaceTests: XCTestCase {

    var implToTest: Interface!

    func testMethodOne() {
        ...
    }

    func testMethodTwo() {
        ...
    }
}

但是在这里,这些测试也会被执行,并且它们会失败,因为没有将实现分配给implToTest。当然,我可以为其分配一些实现,但是我将以两个测试用例结束相同的实现。最好的选择是以某种方式禁用InterfaceTests 测试用例并只运行它的子类。有可能吗?

我得到的第三个想法可能看起来很棘手,但它会满足我的所有需求。不幸的是,它不起作用。 我决定创建InterfaceTestable 协议:

protocol InterfaceTestable {
    var implToTest: Interface! { get set }
}

并通过所有共享测试对其进行扩展:

extension InterfaceTestable {

    func testMethodOne() {
        ...
    }

    func testMethodTwo() {
        ...
    }
}

然后为每个实现创建测试用例:

class ImplementationATests: XCTestCase, InterfaceTestable {

    var implToTest: Interface!

    override func setUp() {
        super.setUp()
        implToTest = ImplementationA()
    }

    // some tests which only apply to ImplementationA
}


class ImplementationBTests: XCTestCase, InterfaceTestable {

    var implToTest: Interface!       

    override func setUp() {
        super.setUp()
        implToTest = ImplementationB()
    }

    // some tests which only apply to ImplementationB
}

那些测试用例可以编译,但 Xcode 看不到在 InterfaceTestable 扩展中声明的测试。

还有其他方法可以为不同的实现共享测试吗?

【问题讨论】:

  • 非常有用的问题。建议:将问题编辑为问题中的最小问题陈述。为您的 3 种方法中的每一种添加“答案”。然后人们可以投票和讨论每个人。

标签: swift unit-testing xctest


【解决方案1】:

我遇到了同样的问题,并使用您的第二个选项解决了它。 但是,我找到了一种方法来阻止基类中的测试用例运行:

覆盖基类中的defaultTestSuite() 类方法以返回一个空的XCTestSuite

class InterfaceTests: XCTestCase {

  var implToTest: Interface!

  override class func defaultTestSuite() -> XCTestSuite {
    return XCTestSuite(name: "InterfaceTests Excluded")
  }
}

这样就不会运行来自InterfaceTests 的测试。不幸的是,也没有测试ImplementationATests。通过在ImplementationATests 中覆盖defaultTestSuite() 可以解决此问题:

class ImplementationATests : XCTestCase {

  override func setUp() {
    super.setUp()
    implToTest = ImplementationA()
  }

  override class func defaultTestSuite() -> XCTestSuite {
    return XCTestSuite(forTestCaseClass: ImplementationATests.self)
  } 
}

现在ImplementationATests 的测试套件将运行来自InterfaceTests 的所有测试,但不会直接运行来自InterfaceTests 的测试,无需设置implToTest

【讨论】:

【解决方案2】:

我以前这样做的方式是使用共享基类。使 implToTest 可空。在基类中,如果没有提供实现,只需在保护子句中将return 排除在测试之外。

测试运行包含基类测试的报告,但它没有做任何事情,这有点烦人。但这是一个小烦恼。测试子类将提供有用的反馈。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-06-22
    • 1970-01-01
    • 2019-02-11
    • 1970-01-01
    • 2011-01-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多