Skip to content

JUnit5 support for the existing soft-assertions support (Expect.create JUnit4 Rule) #893

Open

Description

@astubbs

From a purely JUnit5 perspective, am I missing something?

I made this wrapper around the core Expect function:

    public class ThingyThing {
        public static void softly(final SoftAssertions softly) throws Throwable {
            Expect expect = Expect.create();
            expect.apply(new Statement() {
                @Override
                public void evaluate() throws Throwable {
                        softly.apply(expect);
                }
            }, Description.EMPTY)
                    .evaluate();
        }

        public interface SoftAssertions{
            void apply(final Expect expect);
        }
    }

Used like:

        ThingyThing.softly(expector -> {
            expector.that(1).isEqualTo(2);
            expector.that(-1).isGreaterThan(0);
        });

Outputs:

2 expectations failed:
  1. expected: 2
     but was : 1
     	at io.<snip>.ThingTest.lambda$testRemit$0(ThingTest.java:113)
     
  2. expected to be greater than: 0
     but was                    : -1
     	at io.<snip>.ThingTest.lambda$testRemit$0(ThingTest.java:114)

P.s. amazing framework BTW - beautiful. Especially for chained custom objects. Amazing. Wish I'd found it sooner.

Activity

  1. changed the title [-]Nicer way to support soft assertions (Expect.create) in JUnit5?[/-] [+]Nicer way to support soft assertions (Expect.create junit4 Rule) in JUnit5?[/+] on Jul 27, 2021
  2. cpovirk commented on Jul 27, 2021

    @cpovirk
    Member

    Thanks. As you've seen, JUnit 5 is a giant TODO for us, one that we're unlikely to carve off time for in the near future :(

    I can say one slightly encouraging thing, which is that your proposal looks useful even to non-JUnit-5 users. (Maybe we've even heard requests for it from such users? I can't seem to find any offhand, though.) Then I can say one more discouraging thing, which is that we have had a proposal open inside Google for something like this for a couple years, and we haven't acted on it. Now, that proposal was more about adding context to a group of assertions:

    try (TruthContext ctx = Truth.addFailureMessage("foo %s", bar)) {
      ...
    }
    

    If we take into account that such a feature could support all of...

    • context to add to failure messages
    • Expect-style failure collection for...
      • users of JUnit 5 (and other non-JUnit-4 frameworks)
      • users of any framework who simply want to group assertions at a smaller scope than a whole test

    ...then that provides at least a little more motivation.

    Still probably not a big priority for us, given that Truth itself continues not to be a big priority for us, sadly.

  3. ephemient commented on Aug 17, 2021

    @ephemient

    I created PR #706 over a year ago which enables

    @Test
    public void test(StandardSubjectBuilder expect) {
      expect.that(1).isEqualTo(2);
      expect.that(-1).isGreaterThan(0);
    }

    in JUnit 5. I think that makes sense if you're actually using JUnit 5, but if you want to use it in any test framework, then your ThingyThing seems reasonable.

  4. astubbs commented on Sep 2, 2021

    @astubbs
    Author

    @ephemient that seems great! Perhaps the two could be merged to enable both options...

    @cpovirk have you seen #706 ?

  5. ddaeyeonkim commented on Oct 1, 2021

    @ddaeyeonkim

    My solution Inspired by ThingyThing.

    class ExpectExtension : BeforeEachCallback, AfterEachCallback, InvocationInterceptor,
                            ParameterResolver {
    
        private var _expect: Expect? = null
    
        val expect: Expect
            get() = _expect!!
    
        override fun beforeEach(context: ExtensionContext) {
            _expect = Expect.create()
        }
    
        override fun interceptTestMethod(
            invocation: InvocationInterceptor.Invocation<Void>,
            invocationContext: ReflectiveInvocationContext<Method>,
            extensionContext: ExtensionContext
        ) {
            _expect?.apply(
                object : Statement() {
                    override fun evaluate() {
                        invocation.proceed()
                    }
                },
                Description.EMPTY,
            )?.evaluate()
        }
    
        override fun afterEach(context: ExtensionContext) {
            _expect = null
        }
    
        override fun supportsParameter(
            parameterContext: ParameterContext,
            extensionContext: ExtensionContext
        ): Boolean {
            val paramType = parameterContext.parameter.type
            return paramType is Type && paramType == Expect::class.java
        }
    
        override fun resolveParameter(
            parameterContext: ParameterContext,
            extensionContext: ExtensionContext
        ): Any {
            return expect
        }
    }

    A.

    @Test
    @ExtendWith(ExpectExtension::class)
    fun test(expect: Expect) {
        expect.that<Int>(1).isEqualTo(2)
        expect.that<Int>(1).isEqualTo(3)
        expect.that<Int>(1).isEqualTo(4)
    }

    B.

    @JvmField
    @RegisterExtension
    val extension = ExpectExtension()
    
    @Test
    fun test2() {
        extension.expect.that<Int>(1).isEqualTo(2)
        extension.expect.that<Int>(1).isEqualTo(3)
        extension.expect.that<Int>(1).isEqualTo(4)
    }
    
    @Test
    fun test3(expect: Expect) {
        expect.that<Int>(1).isEqualTo(2)
        expect.that<Int>(1).isEqualTo(3)
        expect.that<Int>(1).isEqualTo(4)
    }

    I look forward to any form of Expect Extension for JUnit5 being added in the future!

  6. cpovirk commented on Oct 19, 2021

    @cpovirk
    Member

    As belatedly noted on #894, anything that we label as P3 has no timeline for being reviewed :( We hope to eventually schedule some more time for Truth (especially for features that could work well in Kotlin, like this one), but there are no plans yet.

    (Another thing we should do: Figure out if this feature request and #266 represent different requests or if they could be merged.)

  7. changed the title [-]Nicer way to support soft assertions (Expect.create junit4 Rule) in JUnit5?[/-] [+]JUnit5 support for the existing soft-assertions support (Expect.create JUnit4 Rule)[/+] on Feb 5, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions