-
Notifications
You must be signed in to change notification settings - Fork 52
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
Remove try-catch-fail blocks from unit tests #370
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JUnit reports assertion failures differently from uncaught exceptions.
Uncaught exceptions are considered a worse failure mode as they can indicate that the test itself failed to evaluate its criteria. So this could unintentionally increase the apparent severity of test failures.
In JUnit 5 the idiomatic way of dealing with a catch
containing a fail
would be to translate into Assertions.assertDoesNotThrow()
.
So if I am understanding this correctly instead of getting rid of the |
Ok the latest changes almost complete the recipe. There are only two issues remaining; The first being that the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@AlekSimpson I added a few hints which should allow you to make progress.
src/test/java/org/openrewrite/java/testing/junit5/RemoveTryCatchBlocksFromUnitTestsTest.java
Outdated
Show resolved
Hide resolved
src/test/java/org/openrewrite/java/testing/junit5/RemoveTryCatchBlocksFromUnitTestsTest.java
Outdated
Show resolved
Hide resolved
src/main/java/org/openrewrite/java/testing/junit5/RemoveTryCatchBlocksFromUnitTests.java
Outdated
Show resolved
Hide resolved
…ock with Assertions.assertDoesNotThrow() block
eb818b9
to
b21fe0e
Compare
src/main/java/org/openrewrite/java/testing/junit5/RemoveTryCatchBlocksFromUnitTests.java
Outdated
Show resolved
Hide resolved
…s the try-catch block
src/main/java/org/openrewrite/java/testing/junit5/RemoveTryCatchBlocksFromUnitTests.java
Outdated
Show resolved
Hide resolved
src/main/java/org/openrewrite/java/testing/junit5/RemoveTryCatchBlocksFromUnitTests.java
Outdated
Show resolved
Hide resolved
src/main/java/org/openrewrite/java/testing/junit5/RemoveTryCatchBlocksFromUnitTests.java
Outdated
Show resolved
Hide resolved
@knutwannheden, Ok I made those changes you suggested. One thing though that I am still not sure about here is that two of the tests are not passing because its throwing an error when it reaches the |
Looking at the code I would probably get rid of the I am also saying this because I know that test code is frequently made more modular by factoring out some assertions into helper methods. And then these would not get refactored. So I suggest we remove the matchers and leave the Meanwhile I will look at your template problem. It could be a bug in the template engine. |
src/test/java/org/openrewrite/java/testing/junit5/RemoveTryCatchBlocksFromUnitTestsTest.java
Outdated
Show resolved
Hide resolved
Co-authored-by: Knut Wannheden <knut@moderne.io>
Skimmed through a bit, but I'm fine replacing any I do wonder a bit if we should do anything about the potential information loss in - try {
- int divide = 50 / 0;
- }catch (ArithmeticException e) {
- Assert.fail(e.getMessage());
- }
+ Assertions.assertDoesNotThrow(() -> {
+ int divide = 50 / 0;
+ }); Perhaps we should adopt either of these to retain the failure message? Which then can't use the exception anymore(!). |
Ya I've been wondering about that too. Also try-catch blocks could have multiple catch blocks I believe. Something like |
@knutwannheden when you get a chance to look into the possible template engine issue, could you let me know how that goes? |
I just had another look. With the current code I cannot detect any exceptions thrown by the test. So it is hard to determine if there is indeed a bug or just a usage error. Regarding the discussion with the catch blocks: I think we should maybe instead migrate to AssertJ here, as it offers more options which don't lose these details. For example: assertThatCode(() -> {
throw new RuntimeException("e");
}).isNotInstanceOf(IllegalArgumentException.class); or when we don't want any exception: assertThatCode(() -> {
throw new RuntimeException("e");
}).doesNotThrowAnyException(); or for when the code is expected to throw an exception and we want to make an assertion about it: assertThatThrownBy(() -> {
throw new RuntimeException("e");
}).isInstanceOf(RuntimeException.class); |
@knutwannheden I know that when replacing the body of a method with a new body you would use the |
@AlekSimpson Since you in your case replace the entire |
Ok the template error issue is fixed, I just needed to add |
src/main/java/org/openrewrite/java/testing/junit5/RemoveTryCatchBlocksFromUnitTests.java
Outdated
Show resolved
Hide resolved
private static class RemoveTryCatchBlocksFromUnitsTestsVisitor extends JavaVisitor<ExecutionContext> { | ||
@Override | ||
public J visitTry(J.Try try_, ExecutionContext ctx) { | ||
if (try_.getCatches().get(0).getBody().getStatements().stream().noneMatch( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- We seem to imply here that we only ever look at the first
catch
block;
I'd appreciate a test that uses two catch blocks, and appropriate handling (skip?) - Have you given any thought to try-with-resources blocks? We would not want to remove those.
Might be good to add in a test that usestry (Foo bar) { ... } catch (Exception e) { fail(); }
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes I am not sure how we should handle try statements with multiple catch blocks. Did you see Knut's comment about using AssertJ instead? What are your thoughts on that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There might be value in having a separate recipe for AssertJ, but not everyone is ready or willing to use that just yet. To me it then makes the most sense to check here that there is:
- only one catch block, such that we know it's safe to apply this recipe
- only one statement in the catch block, which is a
fail()
, with no or a simple String argument. We would not want to convert for instancefail(cleanUpAndReturnMessage())
might still have side effects that we don't want to remove.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm; considering number two above: Assert.fail(e.getMessage())
should be fine.. It's not easy thinking of each possible scenario 😅
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There might be value in having a separate recipe for AssertJ, but not everyone is ready or willing to use that just yet. To me it then makes the most sense to check here that there is:
1. only one catch block, such that we know it's safe to apply this recipe 2. only one statement in the catch block, which is a `fail()`, with no or a simple String argument. We would not want to convert for instance `fail(cleanUpAndReturnMessage())` might still have side effects that we don't want to remove.
Latest commit addresses this
src/test/java/org/openrewrite/java/testing/junit5/RemoveTryCatchBlocksFromUnitTestsTest.java
Outdated
Show resolved
Hide resolved
src/test/java/org/openrewrite/java/testing/junit5/RemoveTryCatchBlocksFromUnitTestsTest.java
Outdated
Show resolved
Hide resolved
…chBlocksFromUnitTestsTest.java Co-authored-by: Tim te Beek <tim@moderne.io>
…chBlocksFromUnitTestsTest.java Co-authored-by: Tim te Beek <tim@moderne.io>
… the added conditions
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There's been a bit of an unfortunate oversight earlier in the use of JUnit 4 Assert, whereas we're more likely to execute this recipe after a JUnit 5 migration, as part of the best practice recipes. Could you update the PR once more to reflect this change?
src/main/java/org/openrewrite/java/testing/junit5/RemoveTryCatchFailBlocksFromUnitTests.java
Outdated
Show resolved
Hide resolved
src/main/java/org/openrewrite/java/testing/junit5/RemoveTryCatchFailBlocksFromUnitTests.java
Outdated
Show resolved
Hide resolved
src/main/java/org/openrewrite/java/testing/junit5/RemoveTryCatchFailBlocksFromUnitTests.java
Outdated
Show resolved
Hide resolved
src/main/java/org/openrewrite/java/testing/junit5/RemoveTryCatchFailBlocksFromUnitTests.java
Outdated
Show resolved
Hide resolved
src/main/java/org/openrewrite/java/testing/junit5/RemoveTryCatchFailBlocksFromUnitTests.java
Outdated
Show resolved
Hide resolved
...test/java/org/openrewrite/java/testing/junit5/RemoveTryCatchFailBlocksFromUnitTestsTest.java
Outdated
Show resolved
Hide resolved
...test/java/org/openrewrite/java/testing/junit5/RemoveTryCatchFailBlocksFromUnitTestsTest.java
Outdated
Show resolved
Hide resolved
…chFailBlocksFromUnitTestsTest.java Co-authored-by: Tim te Beek <tim@moderne.io>
Ok @timtebeek let me know how these new changes look. |
What's changed?
This PR adds a new recipe to move exception to the method signature when there is a try catch block inside of a unit test method.
What's your motivation?
#216
Anything in particular you'd like reviewers to focus on?
I left a comment marking this but I see that the
withThrows()
method takes in a list ofNameTree
types. I can't seem to find how to get thatNameTree
type from theJ.Catch
block. I thought maybe the.getExceptions()
method is what I should use but that returns anExpression
. Is there maybe some way to convert that to aNameTree
?Anyone you would like to review specifically?
@timtebeek
Any additional context
RSPEC-3658
Checklist
./gradlew licenseFormat