-
Notifications
You must be signed in to change notification settings - Fork 260
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Grouping assertions dynamically #266
Comments
This is an interesting idea... /cc @cpovirk @PeteGillinGoogle |
This sounds rather similar to JUnit 5's |
Yeah, this is something that I've wanted before. I think it's useful even for JUnit tests, because it's more targeted than Expect (you can say "run all of this logical group of assertions, but don't run this second group which would be meaningless if the first group fails"... the failure messages of Expect are already kind of awful a lot of the time, and adding in noise from all the later tests you don't care about can make them much worse — this has often been enough to steer me away from using Expect, and just doing some debugging to figure out which of the other tests pass when the first fails). After reading your proposal, I was going to float an alternative, adding a method like Subject.satisfiesAllOf(Assertion<? super S>... assertions) where Assertion is a functional interface a bit like a throwing Consumer. Example usage:
This supports other test verbs and custom subjects in the natural way, so the equivalent of your example would be like this:
(The implementation of satisfiesAllOf would have to do an unchecked cast of 'this' to S, because Generics, but we already have precedent for that.) However, I suspect that the presence of assertAll in JUnit5 (thanks for the pointer, @jbduncan) makes this a lot less appealing. With Truth and JUnit5 as they currently stand, you could write my example as:
and your example as:
Comparing your proposal, my proposal, and what's available for free once JUnit5 lands, what are the arguments in favour of doing something in Truth?
I'm not sure how compelling those arguments are. I'd love to know what @kluever and @cpovirk think — and you, @bnorm. (JUnit5 API for reference: http://junit.org/junit5/docs/current/api/org/junit/jupiter/api/Assertions.html) |
Incidentally, @bnorm, can you say anything more about the difficulties you're having with your own implementation of GroupVerb? I don't see right now why the visibility of AbstractVerb.getFailureStrategy() is an issue for you. I think this works:
and then you just need to implement GroupFailureStrategy which overrides fail(String, Throwable) to capture the failure and implements executeDeferredFailures to delegate to the FailureStrategy passed into the constructor (somehow rolling up all of the captured failures). |
That is exactly the working prototype I have. But if GroupVerb is in any package other than I do like the flow of |
Oops, I had totally failed to spot that my prototype only worked because I'd tried it in the same package :-). Sorry about that. It's kind of annoying. If it weren't for the fact that you need to implement the (String, Throwable) overload of FailureStrategy.fail, you could do it by delegating to the AbstractVerb's fail method, which you do have access to. It seems like a bit of an oversight that AbstractVerb has methods which forward to only 2 of the 3 overloads on FailureStrategy. However, the very existence of that overload is a bit weird — as far as I can tell, it's never used within Truth itself with a non-null Throwable. There are a handful of callers elsewhere in the Google codebase (from within Subject subclasses, where you do have access to the FailureStrategy) but it's against the Truth idiom. So, in practical terms, I think you could implement GroupFailureStrategy by having fail(String) delegate to the original AbstractVerb (which you do have access to) and having fail(String, Throwable) either throw an UnsupportedOperationException; or you could do it by having fail(String, Throwable) ignore the Throwable and delegate to the AbstractVerb... Unless you're using a custom Subject which calls the fail(String, Throwable) overload, you're not going to get any problems. (I agree this isn't ideal.) |
But we're digressing somewhat... You make a reasonable point about my proposal being restricted to assertions about one subject, whereas your proposal is more general at the expense of being more verbose. I think there'd be a useful discussion to be had — but only if we've convinced ourselves that either of them is worth doing given the imminent arrival of assertAll. |
I don't have an intuitive feel for how often this comes up, so I should probably give it some more thought. At the moment, we're pondering some changes to the failure APIs, |
I like this idea too, though I agree with Chris that I don't think it's likely to come up in practice all that often. I worry that it could encourage people to write overly-complex test methods, whereas One question; can we think of a better name than "GroupVerb"? The name should ideally (a) read naturally like |
The Expect TestVerb is great for short JUnit tests but I write non-JUnit system tests that run for hours. I would like to use Truth for all the assertion checks I make throughout my tests but I want a way to be able to group some checks together so I get as much information at the point of failure while still stopping the test at the point of failure.
Sort of the design I'm thinking is this
Checks made with a GroupVerb are gathered like with
Expect
and when GroupVerb is "closed," the group failures are packaged like Expect and sent to the failure strategy of the wrapped test verb. I could use this to check multiple properties on the same subject or even iterate a list of subjects, checking them all.I have a working prototype for GroupVerb but it requires being in the
com.google.common.truth
package becausegetFailureStrategy()
onAbstractVerb
is protected. I thought this might be a good feature for the library though.The text was updated successfully, but these errors were encountered: