0

In a unit test, I want to assert that a method that has the potential to throw an index out of range error actually throws that error.

I'm trying to use

let array = [1,2,3]
XCTAssertThrowsError(array[3])    

Why doesn't this work?

How do I test this?

Joe Susnick
  • 6,544
  • 5
  • 44
  • 50
  • not sure, but I think it's meant for errorHandling as for objects that conform to `Error`, not actual errors like this. – mfaani Mar 02 '17 at 21:25
  • 3
    It's not working because it's not throwing an error, but rather its an exception, which is a completely different thing. – Rob Mar 02 '17 at 21:26
  • 1
    there's also this question http://stackoverflow.com/questions/32873212/unit-test-fatalerror-in-swift that has some approaches for unit testing `fatalError()` – MathewS Mar 02 '17 at 21:27
  • @Rob is this the kind of thing we should actually be doing testing for?! It's like testing if the exceptions of the Swift language is working itself... – mfaani Mar 02 '17 at 21:29
  • 1
    @Honey - No, you don't write unit tests to test for exceptions/faults/crashes in Swift. If there's a particular error situation you want to handle, write app code to gracefully handle that in such a way that prevents the crash, and then test that. – Rob Mar 02 '17 at 22:57
  • What does the method that you want to test look like? If there is no way to make it fail by passing in arguments then, it is not something you can unit test. – nycynik Mar 02 '17 at 23:22
  • @nycynik Basically trying to access a cell at an IndexPath where the cellForRow method uses an array to populate data. I know the right way is to do the check in that method but it got me thinking about how to test this in general. – Joe Susnick Mar 03 '17 at 21:26
  • @Rob I think Honey is right, you want to be able to test that your throwing functions are working correctly. But I also see your point about not having code that you expect to crash the app since that's a situation you should ALWAYS avoid. – Joe Susnick Mar 03 '17 at 21:30
  • @JoeSusnick - "you want to be able to test that your throwing functions". Yep, you should test functions that truly `throw` errors with `XCTAssertThrowsError`. But your example is not "throwing" an error. It's failing an internal validation (e.g. on Intel processors, it generates `ud2` opcode which causes an `EXC_BAD_INSTRUCTION`). `XCTAssertThrowsError` is not designed to catch that. You don't write tests to handle this scenario. You write code that cannot do this. – Rob Mar 03 '17 at 21:56

1 Answers1

4
let array = [1,2,3]
XCTAssertThrowsError(array[3])    

Why doesn't this work?

Because referring to an out of bounds index does not throw. It crashes, which is a completely different thing.

How do I test this?

How do you test what? If the question is whether a proposed index is legal for a given array, use indices.contains:

let array = [1,2,3]
let ix = 3
XCTAssert(array.indices.contains(ix), "Index out of bounds")
matt
  • 515,959
  • 87
  • 875
  • 1,141
  • I accepted because this is a good answer for testing whether an index is out of bounds or not, but it still doesn't answer how to rescue a FatalError/crash/etc... Really my question was phrased incorrectly. :) – Joe Susnick Mar 03 '17 at 21:27
  • 2
    You're right, it was phrased incorrectly. You cannot "rescue a fatal error / crash", and that has been dealt with here on Stack Overflow many times already. That is why my answer says that it is up to _you_ to test the bounds _before_ you use an out of bounds expression. It's just like `as!` vs. `as?`; you can use `as?` to test, but if you don't and you use `as!` and the cast fails, you _will crash_ and you _cannot prevent it_. – matt Mar 03 '17 at 22:09
  • This is a clever solution getting the indices (a Range). Learn something new every day ;) – John Aug 08 '22 at 20:09