#2332 Test.verifyErr()

SlimerDude Sat 23 Aug 2014

Test.verifyErr() currently:

Verifies that the function throws an Err of the exact same type as err (compare using === operator).

Wouldn't it be more useful if the Err type was compared with fits() so you could specify a super class of the thrown Err? Example, if you have the following Err hierarchy:

Err
 ↑
ArgErr
 ↑
MyErr

It would be up to you (the tester) to decide which Err you wanted to test the presence for. Then all these examples would pass:

verifyErr(Err#)    { throw MyErr() }  // case 1
verifyErr(ArgErr#) { throw MyErr() }
verifyErr(MyErr#)  { throw MyErr() }

Use case, sometimes you don't particularly care which Err was thrown, just that one was thrown, so you'd use case 1 above.

Other times the Err type is not available to you because it's internal to some other pod. TestErr itself being a prime example. (Which I needed to test in Concordion.) My workaround was to use reflection, simple but messy:

verifyErr(Type.find("sys::TestErr")) { ... }

brian Sat 23 Aug 2014

I actually like it testing a specific class because typically I want to verify the API is throwing the exact error I am expecting

SlimerDude Tue 26 Aug 2014

I want to verify the API is throwing the exact error I am expecting

Pretty much, you still can. Tests that throw different Errs still fail:

verifyErr(ArgErr#) { throw ParseErr() }  // --> Fail

You can still verify the Err subclass:

Err
 ↑
SubErr

verifyErr(SubErr#)  { throw Err() } // --> Fail

The only difference being if, at a later date, a sub-sub Err class is thrown:

Err
 ↑
SubErr
 ↑
SubSubErr

verifyErr(SubErr#)  { throw SubSubErr() } // --> Pass

And I would say that's not wrong, because SubSubErr is a SubErr.

brian Tue 26 Aug 2014

Its really a question of testing a API contract versus true whitebox testing. You are thinking of it as the former, I am thinking about it as the later. For example to me, that method should match the behavior of verifyType. But I can see other way too if you can convince a couple others like Andy and Matthew

andy Tue 26 Aug 2014

I don't really use Err subclasses - so can't say I really have an opinion here.

SlimerDude Tue 26 Aug 2014

can't say I really have an opinion here.

Andy, I have a beer here with your name on it... are you sure!? :D

brian Fri 5 Sep 2014

After thinking about this more, I'm not sure the proposal makes sense. If you are testing specific conditions, why wouldn't you want to test the specific exception type thrown? You are writing each test for a specific scenerio, why would you test the types generically?

SlimerDude Wed 17 Sep 2014

why would you test the types generically?

I admit it's not often, but these are 2 reasons in particular that I (personally) have wanted to... (not that I'm saying they're good reasons!):

  1. Lazyness.

    Sometimes it's good enough to know that an Err is thrown, or more specifically to test that an IocErr is thrown. I have subtypes of IocErr that are public but @NoDoc. Testing the exact subtype becomes fiddly but testing for IocErr is cut'n'paste consistent and complies to the documentation.

  2. Internal Errs from other Pods

    While writing Fancordion I was testing that a TestErr was thrown / propagated. As TestErr is internal to sys it would have been easy (and suffice) enough to just test for an Err with a specific message.

In general the proposal gives the developer more options, and I couldn't see a scenario when generic testing would pose a problem.

It is also more in line with actual usage; try / catch blocks. The catch mechanism uses fits so I figure the test should too.

it's a question of testing a API contract versus true whitebox testing.

True... Going back to case 1, if I document a method as throwing an IocErr but it actually throws IocInnerErr which extends IocErr, then an acceptance test should test for IocErr. More over, should the hierarchy of IocInnerErr change to extend ArgErr then the acceptance test would fail whereas the whitebox test would still pass.

Anyway, despite all the ranting above, I know my arguments are weak! I'm happy to leave it as is if you're still not convinced.

brian Thu 18 Sep 2014

One thing we could do that would keep the functionality that I want is to make the error type parameter nullable and if you pass in null it just checks that any exception type was thrown.

andy Thu 18 Sep 2014

One thing we could do that would keep the functionality that I want is to make the error type parameter nullable and if you pass in null it just checks that any exception type was thrown.

Yeah I like that

SlimerDude Tue 23 Sep 2014

Hmm... yeah, that sounds like a good compromise!

brian Tue 23 Sep 2014

Yeah I like that design. I implemented it and pushed it

Login or Signup to reply.