26

I'm writing Cocoa unit tests using XCTest and recently used XCTAssertThrows for the first time. That's pretty cool, but I want to make it even better with XCTAssertThrowsSpecific and requiring a certain exception.

Here is an example test:

-(void)testShortPassword {
    XCTAssertThrows([user storePassword:@"abc"],@"Expect exception for short pw");
}

And on my user class I have the following code:

-(void)storePassword:(NSString*)password {

    NSCAssert(password.length > 6, @"Password must be longer than 6 characters");

    // go on to store the password on the keychain
}

Keeping in mind that Cocoa in general shies away from using exceptions (so it might be better to return an error, and show UI in the preceding example, etc.) How do I throw an exception in a manner that can be caught by XCTAssertThrowsSpecific? How do I specify that in XCTAssertThrowsSpecific(expression, specificException, format...)?

owenfi
  • 2,471
  • 1
  • 24
  • 37

1 Answers1

35

You should only use exceptions for exceptional cases, not for error handling and flow control

Having said that, here's how you use XCTAssertThrowsSpecific:

XCTAssertThrowsSpecific expects the specific class of the exception as the second parameter. NSCAssert throws an NSException. To test for that, use

XCTAssertThrowsSpecific([object methodThatShouldThrow], NSException, @"should throw an exception");

Now, that won't help much, because it's likely that every exception is an NSException or a subclass thereof.

NSExceptions have a name property that determines the type of the exception. In case of NSCAssert this is NSInternalInconsistencyException. To test for that, use XCTAssertThrowsSpecificNamed

XCTAssertThrowsSpecificNamed(
  [object methodThatShouldThrow],
  NSException,
  NSInternalInconsistencyException,
  @"should throw NSInternalInconsistencyException"
);
JOM
  • 8,139
  • 6
  • 78
  • 111
Sebastian
  • 7,670
  • 5
  • 38
  • 50
  • do you still think this since Swift 2.0? Thanks – DogCoffee Aug 21 '15 at 07:23
  • Swift 2 doesn't add *exception* handling, it adds _error_ handling. The main semantic difference is that exceptions are unrecoverable, whereas errors are can be handled gracefully. – Sebastian Aug 21 '15 at 23:06
  • 3
    Thanks, also FYI XCTAssertThrowsSpecificNamed isn't in Swift 2.0 – DogCoffee Aug 21 '15 at 23:54
  • 1
    @Sebastian could you elaborate on why you avoid using Exceptions for error-handling? I too, use them for validation and they've helped keep things neat so far - is the performance penalty massive? – Angad Jun 30 '16 at 14:12
  • 3
    In short, because Apple says so: https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/Exceptions/Exceptions.html#//apple_ref/doc/uid/10000012-BAJGFBFB – Sebastian Jul 01 '16 at 00:59
  • How can I use this in swift , because I just started iOS and I don't the objective C. Please help me out – Ronak Patel Dec 17 '19 at 04:19