【问题标题】:Swift - Display assertion failures inline in Xcode like XCTest failures?Swift - 在 Xcode 中内联显示断言失败,如 XCTest 失败?
【发布时间】:2019-04-11 13:38:10
【问题描述】:

我想编写一些自定义测试断言类型并让它们显示在 Xcode 中,类似于 XCTAssert() 失败的显示方式:

有没有办法让我加入 Xcode 并实现这一点?

我希望我自己的断言函数在此处以同样的方式显示其错误:

到目前为止,我发现的最好的资源是 Apple 的 XCTest source code,但我无法理解它是否包含负责显示错误 UI 的逻辑。

【问题讨论】:

    标签: ios swift xcode xctest


    【解决方案1】:

    最简单的方法是从您的自定义断言中调用XCTFail(),但传递调用站点的文件名和行号。例如:

    func verify(myThing: MyThing, file: StaticString = #filePath, line: UInt = #line) {
       // Do your verification. Then when you want to fail the test,
       XCTFail("Some message about \(myThing)", file: file, line: line)
    }
    

    在调用站点,您可以让默认参数提供fileline。所以它看起来像:

    verify(myThing: thing)
    

    在 Swift 中,XCTest 断言是全局函数。这意味着您的助手也可以是一个全局函数,并在测试套件之间共享,而不必继承 XCTestCase

    【讨论】:

    • XCTFail 似乎使用的是#filePath 而不是#file。它可能也应该用作验证的默认参数。
    • Xcode 12 的更新答案。谢谢@Daniel
    【解决方案2】:

    完全可以做你想做的事,我只是设法做到了,像这样:

    使用recordFailure

    您可以通过在任何测试中调用recordFailure 来实现您想要的(继承自标准XCTestCase)。

    更短的语法

    要么扩展XCTestCase

    如果你想简化对这个函数的调用,你可以编写一个扩展函数来包装它。

    或子类

    你也可以继承XCTestCase(如果你想共享一些设置,这可能是个好主意,在setup中调用,那么你只需要在这个新的超类中对你的测试类进行)。

    class TestCase: XCTestCase {
    
      func forwardFailure(
            withDescription description: String = "Something went wrong",
            inFile filePath: String = #file,
            atLine line: Int = #line,
            expected: Bool = false
        ) {
            self.recordFailure(
                withDescription: description,
                inFile: filePath,
                atLine: line,
                expected: expected
            )
        }
    
    }
    

    我不确定如何使用expected: Bool,它是recordFailure method (source) 的必需参数,但看起来Apple 大多将其设置为false

    自定义断言方法

    现在您可以像这样声明您的自定义断言方法(或作为 XCTestCase 的扩展,取决于您的选择):

    
    extension TestCase {
    
        /// Since `Foobar.Type` does not conform to `Equatable`, even if `Foobar` conforms to `Equatable`, we are unable to write `XCTAssertEquals(type(of: foo), Foobar.self)`, this assert method fixes that.
        func XCTAssertType<Actual, Expected>(
            of actual: Actual,
            is expectedType: Expected.Type,
    
            _ filePath: String = #file,
            _ line: Int = #line
        ) {
    
            if let _ = actual as? Expected { return /* success */  }
            let actualType = Mirror(reflecting: actual).subjectType
    
            forwardFailure(
                withDescription: "Expected '\(actual)' to be of type '\(expectedType)', but was: '\(actualType)'",
    
                inFile: filePath,
                atLine: line
            )
        }
    
    }
    
    

    现在它报告错误,不是在自定义断言中,而是在调用站点?。

    使用标准断言方法 + 文件中的转发位置

    如果您查看例如XCTAssertTrue,它接受一个 line 参数和一个 file 参数。

    【讨论】:

      【解决方案3】:

      使用Xcode 12,我们可以使用XCTIssue 内联断言 现有的recordFailure 已弃用。 下面是测试的例子

      import XCTest
      @testable import TestAssertionForward
      
      class TestAssertionForwardTests: XCTestCase {
      
          func testExample() throws {
              assert(actual: 10, expected: 20) // asserts in method
              assert(actual: 10, expected: 11) // asserts in method
              assertInLine(actual: 10, expected: 11) // asserts in line
              assertInLine(actual: 10, expected: 11) // asserts in line
          }
      }
      
      extension TestAssertionForwardTests {
      
          func assert(actual: Int, expected: Int) {
              XCTAssertEqual(actual, expected)
          }
      
          func assertInLine(actual: Int, expected: Int, filePath: String = #file, lineNumber: Int = #line) {
              if actual != expected {
                  let location = XCTSourceCodeLocation(filePath: filePath, lineNumber: lineNumber)
                  let context = XCTSourceCodeContext(location: location)
                  let issue = XCTIssue(type: .assertionFailure,
                                       compactDescription: "\(actual) is not equal to \(expected)",
                                       detailedDescription: nil,
                                       sourceCodeContext: context,
                                       associatedError: nil,
                                       attachments: [])
                  record(issue)
              }
          }
      }
      

      下面是失败断言的截图

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-10-03
      • 1970-01-01
      • 1970-01-01
      • 2011-05-27
      • 1970-01-01
      • 2018-03-12
      • 1970-01-01
      相关资源
      最近更新 更多