Является ли использование генериков действительными в подклассах XCTestCase?
У меня есть подкласс 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 проблемой здесь?
Ответы
Ответ 1
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:
Когда вы создаете класс Swift, который спускается из класса Objective-C, класс и его элементы-свойства, методы, индексы и инициализаторы, которые совместимы с Objective-C, автоматически доступны из Objective-C. Это исключает возможности Swift, такие как перечисленные здесь:
...
Ergo ваш общий подкласс XCTestCase не может использоваться XCTest.
Ответ 2
Ну, на самом деле это полностью выполнимо. Вам просто нужно создать класс, который будет своего рода тестовым бегуном. Например:
class TestRunner: XCTestCase {
override class func initialize() {
super.initialize()
let case = XCTestSuite(forTestCaseClass: ViewControllerTests<WelcomeViewController>.self)
case.runTest()
}
}
Таким образом вы можете выполнить все свои общие тесты.
Ответ 3
У меня получилось работать хакерским способом с протоколами и связанными типами:
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()
}
}