用于不同接口实现的共享 XCTest 单元测试

Seb*_*ski 5 unit-testing xctest swift

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

protocol Interface {
    func methodOne()
    func methodTwo()
}
Run Code Online (Sandbox Code Playgroud)

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

第一个是创建测试用例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()
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

class InterfaceTests: XCTestCase {

    var implToTest: Interface!

    func testMethodOne() {
        ...
    }

    func testMethodTwo() {
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

protocol InterfaceTestable {
    var implToTest: Interface! { get set }
}
Run Code Online (Sandbox Code Playgroud)

并使用所有共享测试对其进行扩展:

extension InterfaceTestable {

    func testMethodOne() {
        ...
    }

    func testMethodTwo() {
        ...
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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
}
Run Code Online (Sandbox Code Playgroud)

这些测试用例可以编译,但 Xcode 没有看到InterfaceTestable扩展中声明的测试。

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

ith*_*ron 6

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

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

class InterfaceTests: XCTestCase {

  var implToTest: Interface!

  override class func defaultTestSuite() -> XCTestSuite {
    return XCTestSuite(name: "InterfaceTests Excluded")
  }
}
Run Code Online (Sandbox Code Playgroud)

有了这个,没有InterfaceTests运行测试。不幸的是也没有任何测试ImplementationATests。通过覆盖defaultTestSuite()ImplementationATests此可以得到解决:

class ImplementationATests : XCTestCase {

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

  override class func defaultTestSuite() -> XCTestSuite {
    return XCTestSuite(forTestCaseClass: ImplementationATests.self)
  } 
}
Run Code Online (Sandbox Code Playgroud)

现在测试套件ImplementationATests将运行所有测试InterfaceTests,但没有测试InterfaceTests直接运行,无需设置implToTest