Skip to content

Conversation

@mpkorstanje
Copy link
Contributor

@mpkorstanje mpkorstanje commented Nov 17, 2025

When using JUnit.start and creating a failing test, users will be confronted with a large stacktrace with mostly irrelevant information. Even after #5158 is merged, the stacktrace will contain several internal frames:

org.opentest4j.AssertionFailedError: expected: <11> but was: <12>
	at org.junit.jupiter.api@6.1.0-SNAPSHOT/org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:158)
	at org.junit.jupiter.api@6.1.0-SNAPSHOT/org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:139)
	at org.junit.jupiter.api@6.1.0-SNAPSHOT/org.junit.jupiter.api.AssertEquals.failNotEqual(AssertEquals.java:201)
	at org.junit.jupiter.api@6.1.0-SNAPSHOT/org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:152)
	at org.junit.jupiter.api@6.1.0-SNAPSHOT/org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:147)
	at org.junit.jupiter.api@6.1.0-SNAPSHOT/org.junit.jupiter.api.Assertions.assertEquals(Assertions.java:558)
	at com.examp.project/com.example.project.HelloTest.stringLength(HelloTest.java:14)

By pruning these internal frames, the stacktrace can be reduced to a much more readable:

org.opentest4j.AssertionFailedError: expected: <11> but was: <12>
	at com.examp.project/com.example.project.HelloTest.stringLength(HelloTest.java:14)

Comparable behaviour can be found in AssertJ[1] and IDEA which folds internal frames in the console using <6 internal lines>.

The pruning functionality is intentionally added to the AssertionFailureBuilder rather than the ExceptionUtils to enable other users to also prune the internal frames from their own assertions.

  1. https://github.com/assertj/assertj/blob/79bdebf1817692e5e0ff5ee3ab097dcd104d47ae/assertj-core/src/main/java/org/assertj/core/util/Throwables.java#L117-L148

I hereby agree to the terms of the JUnit Contributor License Agreement.


Definition of Done

@mpkorstanje mpkorstanje added this to the 6.1.0-M2 milestone Nov 18, 2025
@mpkorstanje mpkorstanje force-pushed the rien/prune-stacktrace-assertion-builder branch from a04dd02 to 94360c1 Compare November 18, 2025 00:41
@mpkorstanje mpkorstanje changed the title Prune internal frames from AssertionFailedError Trim internal frames from AssertionFailedError Nov 18, 2025
When using `JUnit.start` and creating a failing test, users
will be confronted with a large stacktrace with mostly irrelevant
information. Even after #5158 is merged, the stacktrace will contain
several internal frames:

```
org.opentest4j.AssertionFailedError: expected: <11> but was: <12>
	at org.junit.jupiter.api@6.1.0-SNAPSHOT/org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:158)
	at org.junit.jupiter.api@6.1.0-SNAPSHOT/org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:139)
	at org.junit.jupiter.api@6.1.0-SNAPSHOT/org.junit.jupiter.api.AssertEquals.failNotEqual(AssertEquals.java:201)
	at org.junit.jupiter.api@6.1.0-SNAPSHOT/org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:152)
	at org.junit.jupiter.api@6.1.0-SNAPSHOT/org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:147)
	at org.junit.jupiter.api@6.1.0-SNAPSHOT/org.junit.jupiter.api.Assertions.assertEquals(Assertions.java:558)
	at com.examp.project/com.example.project.HelloTest.stringLength(HelloTest.java:14)
```

By pruning these internal frames, the stacktrace can be reduced to a
much more readable:

```
org.opentest4j.AssertionFailedError: expected: <11> but was: <12>
	at com.examp.project/com.example.project.HelloTest.stringLength(HelloTest.java:14)
```

Comparable behaviour can be found in AssertJ[1] and IDEA which folds
internal frames in the console using `<6 internal line>`.

The pruning functionality is intentionally added to the
`AssertionFailureBuilder` rather than the `ExceptionUtils` to enable
other users of the builder to also prune the internal frames from their
own assertions.

1. https://github.com/assertj/assertj/blob/79bdebf1817692e5e0ff5ee3ab097dcd104d47ae/assertj-core/src/main/java/org/assertj/core/util/Throwables.java#L117-L148
@mpkorstanje mpkorstanje force-pushed the rien/prune-stacktrace-assertion-builder branch from 94360c1 to 9e04b51 Compare November 18, 2025 01:26

@Test
@Test //TODO:
void shouldAlwaysKeepJupiterAssumptionStackTraceElement() {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should assumptions also be trimmed?

@marcphilipp
Copy link
Member

marcphilipp commented Nov 18, 2025

I think we should preserve the bottomost Assertions/Assumptions stack frame:

org.opentest4j.AssertionFailedError: expected: <11> but was: <12>
	at org.junit.jupiter.api@6.1.0-SNAPSHOT/org.junit.jupiter.api.Assertions.assertEquals(Assertions.java:558)
	at com.examp.project/com.example.project.HelloTest.stringLength(HelloTest.java:14)

@mpkorstanje
Copy link
Contributor Author

mpkorstanje commented Nov 18, 2025

I'm not convinced that this extra frame is useful. Users will never visit it, because the frame above it is their code and the place they'll ultimately have to fix the issue.

public class HelloTest {

    @Test
    void stringLengthJupiter() {
        org.junit.jupiter.api.Assertions.assertEquals(11, "Hello JUnit2".length());
    }
    @Test
    void stringLengthAssertJ() {
        org.assertj.core.api.Assertions.assertThat("Hello JUnit2".length()).isEqualTo(11);
    }
}

And looking at other projects: IDEA already filters it out. And AssertJ doesn't include it in the first place. edit: As does Google Truth.

Screenshot From 2025-11-18 20-37-41

On a more technical note, for the exceptions thrown by the infline fun in Assertions.kt the stack frames must either start at AssertionFailureBuilder.build or the test method. In which case the latter seems preferable.

What benefits do you think this extra frame adds?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants