【问题标题】:Is use of generics valid in XCTestCase subclasses?在 XCTestCase 子类中使用泛型是否有效?
【发布时间】:2016-05-18 08:22:33
【问题描述】:

我有一个看起来像这样的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 之间的互操作性是这里的问题吗?

【问题讨论】:

  • 我想你已经回答了你自己的问题:setUp 和 test 没有被调用。你的想法看起来很有用。也许你可以尝试实现一个拉取请求:github.com/apple/swift-corelibs-xctest
  • 为什么他们没有被调用,这是个问题。与此同时,我已经实现了一种非常粗糙的方式来做到这一点。让我心潮澎湃。
  • @avisara 你的解决方案是什么?我正在使用 Swift 4,但在使用通用子类时仍然无法运行测试
  • 还没找到。再说一次,也没有积极寻找。
  • 这真是一团糟。我也看到了同样的情况——如果不允许这样做,编译应该会失败而不是浪费一个小时

标签: ios swift generics xctest


【解决方案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() { }
}

【讨论】:

    【解决方案2】:

    我让它以一种 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()
        }
    }
    

    【讨论】:

      【解决方案3】:

      嗯,实际上它是完全可行的。你只需要创建一个类作为测试运行器。例如:

      class TestRunner: XCTestCase {
          override class func initialize() {
              super.initialize()
              let case = XCTestSuite(forTestCaseClass: ViewControllerTests<WelcomeViewController>.self)
              case.runTest()
          }
      }
      

      这样您就可以运行所有的通用测试。

      【讨论】:

      • 从 Swift 5 开始(可能更早)不再适用:Method 'initialize()' defines Objective-C class method 'initialize', which is not permitted by Swift
      【解决方案4】:

      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 子类。

      【讨论】:

      • 这很不幸。此类框架限制应该存在编译时错误。
      • 当然。但请告诉我们,他们究竟是如何猜到这个超限用例的?打开雷达,不要对它们不是的东西进行测试和编译器保护。你自己的技能还是有用的。
      • 另外,现在 XCTest 是开源的 (github.com/apple/swift-corelibs-xctest),您可以在 bugs.swift.org 上贡献或创建一个开放的错误报告
      • 是的,最大。我们可以期待我的答案很快就会过时。
      猜你喜欢
      • 1970-01-01
      • 2013-03-01
      • 2014-10-26
      • 2021-09-21
      • 2014-08-19
      • 1970-01-01
      • 1970-01-01
      • 2014-12-06
      • 2020-04-14
      相关资源
      最近更新 更多