问题
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
回答1:
Perhaps you could use a Test Failure Breakpoint instead of an Exception breakpoint when you are testing. The wwdc 2013 video on unit testing outlined a pretty good workflow for inspecting test failures. It essentially said:
- Set a Test Failure Breakpoint which will allow you to inspect the conditions that caused the failure.
- If needed, set a manual breakpoint earlier in the test and rerun so you can step through the statements leading to the failure as usual.
This isn't really a direct answer, but as far as I know, I don't think there is a way to create exceptions to the exception breakpoint. Hope it helps
回答2:
I had the same issue and I was looking for solution for 2 hours. Probably we can't do anything with that.
回答3:
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))
来源:https://stackoverflow.com/questions/22020527/xctassertthrows-stops-at-breakpoint