Swift-在Xcode中内联显示断言失败,例如XCTest失败?

时间:2018-11-08 03:19:04

标签: ios swift xcode xctest

我想编写一些自定义测试断言类型,并以Xcode显示它们,类似于显示XCTAssert()故障的方式:

我是否有办法挂接到Xcode并实现这一目标?

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

enter image description here

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

3 个答案:

答案 0 :(得分:2)

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

func verify(myThing: MyThing, file: StaticString = #file, 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的子类。

答案 1 :(得分: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
        )
    }

}

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

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

如果您查看例如,您也可以转发line并传递给标准断言。 XCTAssertTrue,它接受​​一个line参数和一个file参数。

答案 2 :(得分:1)

有了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)
        }
    }
}

下面是失败声明的屏幕截图

enter image description here