Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

XCTAssertThrows stops at breakpoint

Tags:

ios

xctest

I'm writing a test method where I want the SUT to throw an exception when under certain conditions. The code looks like this:

- (void) testCantStartTwice
{
    XCTAssertThrows([self.sut start], @"");
}

Now, all is good and the test passes. However, I have Xcode set an Exception Breakpoint for all ObjC exceptions, which is pretty useful when testing out an app in the debugger. As you now, now when I execute my test suite with ⌘U, now it stops at that test and looks like if it's failing, even though it says "Test Succeeded".

Any way of making the breakpoint not stop at that test?

Thanks and all the best

like image 388
Pierluigi Cifani Avatar asked Feb 05 '26 09:02

Pierluigi Cifani


1 Answers

Unfortunately, it does not seem possible to have exception breakpoints ignore anything wrapped in XCTAssertThrows (or now XCTAssertThrowsError).

Workaround 1: Deal with the breakpoints or script around them

When you execute these tests, you can either do the following:

  • Disable the exception breakpoint.
  • Hit run every time it hits one of your breakpoints.

Both are not ideal as you'll be doing some manual work.

There are suggestions for how to disable breakpoints for Swift XCTAssertThrowsError assertions here. I have not tested those.

Workaround 2: Return Result<T, Error> instead

My original method looked like this:

struct Truck {
  static func makeTruck(numberOfWheels: Int) throws -> Self {
    if numberOfWheels < 4 {
      throw TruckError.tooFewWheels
    }

    // ...

    return .init()
  }
}

// Code example:
let truck: Truck? = try? Truck.makeTruck(numberOfWheels: 1)

// Test example:
XCTAssertThrowsError(try Truck.makeTruck(numberOfWheels: 1))

To work around this problem of breakpoints, I created a duplicate internal function that is more testable (since it won't cause the breakpoint problem) by returning a Result instead of throwing an Error.

struct Truck {
  static func _makeTruck(numberOfWheels: Int) -> Result<Truck, Error> {
    if numberOfWheels < 4 {
      return .failure(TruckError.tooFewWheels)
    }

    // ...

    return .success(.init())
  }

  static func makeTruck(numberOfWheels: Int) throws -> Self {
    switch _makeTruck(numberOfWheels: numberOfWheels) {
    case .failure(let error):
      throw error
    case .success(let value):
      return value
    }
  }
}

// Code example:
let truck: Truck? = try? Truck.makeTruck(numberOfWheels: 1)

// Test example:
XCTAssertEquals(Truck._makeTruck(numberOfWheels: 1), .error(TruckError.tooFewWheels))

Workaround 3: Return T? instead

Finally, if you have a simpler use-case, and your function's failure is quite obvious (e.g. there is only one type of error it can return), consider just returning an optional instead of needing the complexity of the Result type:

struct Truck {
  static func makeTruck(numberOfWheels: Int) -> Truck? {
    if numberOfWheels < 4 {
      return nil
    }

    // ...

    return .init()
  }
}

// Code example:
let truck: Truck? = Truck.makeTruck(numberOfWheels: 1)

// Test example:
XCTAssertNil(Truck.makeTruck(numberOfWheels: 1))
like image 95
Senseful Avatar answered Feb 06 '26 23:02

Senseful



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!