我有一个XCTestCase
子类,看起来像这样。为简洁起见,我删除了setup()
和tearDown
方法:
class ViewControllerTests <T : UIViewController>: XCTestCase {
var viewController : T!
final func loadControllerWithNibName(string:String) {
viewController = T(nibName: string, bundle: NSBundle(forClass: ViewControllerTests.self))
if #available(iOS 9.0, *) {
viewController.loadViewIfNeeded()
} else {
viewController.view.alpha = 1
}
}
}
它的子类看起来像这样:
class WelcomeViewControllerTests : ViewControllerTests<WelcomeViewController> {
override func setUp() {
super.setUp()
self.loadControllerWithNibName("welcomeViewController")
// Put setup code here. This method is called before the invocation of each test method in the class.
}
func testName() {
let value = self.viewController.firstNameTextField.text
if value == "" {
XCTFail()
}
}
}
理论上,这应该按预期工作 - 编译器不会抱怨任何事情。但是,当我运行测试用例时,setup()
方法甚至无法被调用。但是,它表示当明确的testName()
方法失败时,测试已经过去了。
泛型的使用是一个问题吗?我可以很容易地想到许多非泛型方法,但我非常想写这样的测试用例。这是XCTest在Objective-C和Swift之间的互操作性问题吗?
答案 0 :(得分:7)
XCTestCase使用Objective-C运行时加载测试类并查找测试方法等。
Swift泛型类与Objective-C不兼容。见https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/InteractingWithObjective-CAPIs.html#//apple_ref/doc/uid/TP40014216-CH4-ID53:
当您创建一个源自Objective-C类的Swift类时,可以从Objective-C自动获得与Objective-C兼容的类及其成员属性,方法,下标和初始化程序。这不包括仅限Swift的功能,例如此处列出的功能:
- 泛型
...
Ergo XCTest无法使用您的通用XCTestCase子类。
答案 1 :(得分:4)
嗯,实际上它是完全可行的。你只需要创建一个类似于测试运行器的类。例如:
class TestRunner: XCTestCase {
override class func initialize() {
super.initialize()
let case = XCTestSuite(forTestCaseClass: ViewControllerTests<WelcomeViewController>.self)
case.runTest()
}
}
这样您就可以运行所有通用测试。
答案 2 :(得分:1)
此方法(https://stackoverflow.com/a/39101121/311889)不再有效。我在Swift 5.2中做到的方式是:
class MyFileTestCase: XCTestCase {
override func run() {
let suite = XCTestSuite(forTestCaseClass: FileTestCase<MyFile>.self)
suite.run()
super.run()
}
// At least one func is needed for `run` to be called
func testDummy() { }
}
答案 3 :(得分:0)
我使它以一种带有协议和相关类型的hacky方式工作:
import XCTest
// If your xCode doesn't compile on this line, download the lastest toolchain as of 30 november 2018
// or change to where Self: XCTestCase, and do it also in the protocol extension.
protocol MyGenericTestProtocol: XCTestCase {
associatedtype SomeType
func testCallRunAllTests()
}
extension MyGenericTestProtocol {
// You are free to use the associated type here in any way you want.
// You can constraint the associated type to be of a specific kind
// and than you can run your generic tests in this protocol extension!
func startAllTests() {
for _ in 0...100 {
testPrintType()
}
}
func testPrintType() {
print(SomeType.self)
}
}
class SomeGenericTestInt: XCTestCase, MyGenericTestProtocol {
typealias SomeType = Int
func testCallRunAllTests() {
startAllTests()
}
}
class SomeGenericTestString: XCTestCase, MyGenericTestProtocol {
typealias SomeType = String
func testCallRunAllTests() {
startAllTests()
}
}