12

How do you write tests for Swift methods that have preconditions? Here is an example:

func doublePositive(n:Int) -> Int {
    precondition(n >= 0)
    return 2*n
}

Using XCTAssertThrowsError does not work:

func testDoublePositive() {
    XCTAssertEqual(10, testObject.doublePositive(5))    // Works
    XCTAssertThrowsError(testObject.doublePositive(-1)) // Breaks 
}

This generates an error when running the test:

Thread 1:EXEC_BAD_INSTRUCTION (Code=EXCI386_INVOP, Subcode=0x0)

Is there a way to test preconditions of Swift?

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • 2
    there is no standard way to "catch" failure in precondition, it will always stop the program, there are some tweaks though , have a look at http://www.cocoawithlove.com/blog/2016/02/02/partial-functions-part-two-catching-precondition-failures.html – ogres Apr 18 '16 at 11:53
  • @ogres Wow, that's a nice article, thanks! – Sergey Kalinichenko Apr 18 '16 at 12:10
  • I can't wait to see this in non-test code. I'm glad this allows you to test what you're trying to test, but I hate that website... because I guarantee there's someone implementing this in their main target and orphaning crashed threads just to prevent the app from crashing... (And I say that, because I've seen it happen for their similar Objective-C article...) – nhgrif Apr 18 '16 at 12:30
  • @nhgrif I wish Apple made it simpler for developers to test preconditions, because they are in the best position to do it. An option to generate exceptions on precondition/assertion failures would do the trick: one would turn it on in debug builds, and turn it off in release builds. Apple could even reject apps compiled with this option turned on if they do not want the catch-all practice to proliferate. – Sergey Kalinichenko Apr 18 '16 at 12:38
  • I agree. It's important for you to be able to test your code... I just know this stuff gets abused. :( – nhgrif Apr 18 '16 at 12:39

1 Answers1

8

You test Swift methods that have preconditions by only testing behavior with inputs that meet those preconditions. The behavior when the precondition is not met is clear without further testing, since preconditions are baked into the standard library.

If you doubt you've correctly specified a precondition, you can pull out the precondition expression into a Boolean function, then test that for correctly discerning valid from invalid inputs.

However, you can create for yourself what you wish for here:

An option to generate exceptions on precondition/assertion failures would do the trick: one would turn it on in debug builds, and turn it off in release builds.

Instead of calling Apple's precondition, you can write your own function, say, require. This could be conditionally compiled to act as you wish. You would then use this everywhere you'd otherwise be using precondition.

Jeremy W. Sherman
  • 35,901
  • 5
  • 77
  • 111