XCTSkip your tests

Description: Get the test results that matter — and skip the ones that don’t. Discover how you can implement XCTSkip to conditionally avoid tests at runtime. We'll take you through how to return this new test result and better document tests beyond pass and fail within your test bundle. To get the most out of this session, you should be familiar with XCTest and unit/UI testing. Watch “Testing in Xcode” for a primer. Once you’ve learned about XCTSkip, learn more about improvements in testing: Watch "Triage test failures with XCTIssue", "Handle interruptions and alerts in UI tests", "Get your test results faster", and "Eliminate animation hitches with XCTest". To learn how to improve your testing suites, check out "Write tests to fail".

Conditional Test Execution

  • Widely used in testing.
  • Determined on runtime.

What's new?

In Xcode 12 we can use XCTSkip for tests that require conditional test execution. It will give us one of the following result:

  • Pass
  • Fail
  • Skip


guard #available(iOS 13.4, *) else {
    throw XCTSkip("Pointer interaction tests can only run on iOS 13.4")

Our test will only run on iOS 13.4 or later: if the device running the test has a lower OS, then XCTSkip will be throw and the test is skipped.

We can also add conditions based on the device:

try XCTSkipIf(UIDevice.current.userInterfaceIdiom != .pad, "Pointer interaction tests are for iPad only")

Tests will be marked with gray color when skipped, and there will be an annotation to track the specified location skipped in the code.

We're also able to check the results from the test navigator and test report. With the test report we can also see the reason why and where is the location of the skipped test

How does it look like in CI? See below:


There are 2 throwing function:

public func XCTSkipIf(
    _ expression: @autoclosure () throws -> Bool, 
    _ message: @autoclosure () -> String? = nil, 
    file: StaticString = #filePath, 
    line: UInt = #line
) throws

public func XCTSkipUnless(
    _ expression: @autoclosure () throws -> Bool, 
    _ message: @autoclosure () -> String? = nil, 
    file: StaticString = #filePath, 
    line: UInt = #line
) throws

Tests also can throw XCTSkip directly:

public struct XCTSkip: Error {

    public init(_ message: String? = nil, file: StaticString = #filePath, line: UInt = #line)


Missing anything? Corrections? Contributions are welcome 😃