gedaiu / fluent-asserts

DLang fluent assertions done right
http://fluentasserts.szabobogdan.com/
MIT License
43 stars 6 forks source link

improve usage of should.throwException #38

Closed linkrope closed 6 years ago

linkrope commented 6 years ago

I can write

foo(0).should.equal(42);

But I cannot just write

foo(1).should.throwException!Exception;

Instead, I have to write it "ugly"

({ foo(1); }).should.throwException!Exception;
DiddiZ commented 6 years ago

Is this even possible, language wise?

As foo(1).should operates on the return value of foo(1), I don't think it would be possible to capture the exception.

linkrope commented 6 years ago

This is how it's done:

auto should(T)(lazy T testData) {
  ...
}

No exception is thrown until testData is evaluated. To postpone the evaluation further, should should wrap testData in a delegate.

gedaiu commented 6 years ago

I had the same idea a while ago and I don't remember why it did not work... I'll look into it again :)

gedaiu commented 6 years ago

@linkrope this would be nice to have but the value is passed in the should function... I think it would be possible to do it, but it needs a lot of refactoring to work.

another way of implementing is to write the assert like this:

foo(1).shouldThrowException!Exception;

where shouldThrowException to be something like this:

auto shouldThrowException(lazy value, string file = __FILE__, size_t line = __line__) {
    return ({  value  }).should.throwException!(E, file, line);
}
linkrope commented 6 years ago

Then, you can even abbreviate the function name: shouldThrow!SomeException reads better than shouldThrowException!SomeException.

In theory, you loose the orthogonality: for each should you have should.not available. In practice, I've never seen should.not.throwExceptionin a real unit test.

In the long run, the refactoring with some kind of "design by introspection" would help. "If it makes sense, it works" is much better than having to look up whether the function you need is implemented.