Junit5: Allow Assertions and Assumptions classes to be extended

Created on 1 Jul 2018  路  16Comments  路  Source: junit-team/junit5

The current class is final and has a private constructor. This means that in order to use its methods without having to qualify them as Assertions.assertEquals/assertTrue/etc... one has to use static imports. In many projects (including ours) this is not allowed due to various concerns (here is neither the place nor the time to discuss them). In _JUnit 4_, the Assert class was not final, so we could easily extend it and use the various _assertXXX_ methods without having to qualify them

public class FooTest extends Assert {
    @Test
    public void testSomething() {
        ....
        assertEquals("Mismatched X and Y", x, y);
    }
}

Unfortunately, we cannot do this with Assertions - which means we cannot use _JUnit 5_ since our project does not allow static imports and we would rather not use qualified access on our 1000's of assertions (again, neither the place nor the time to discuss why...) . It would really help (IMO not just us) if Assertions was extensible...

Jupiter programming model

Most helpful comment

I don't think it would be wise to allow subclassing Assertions because it would blur how it's supposed to be used.

@junit-team/junit-lambda Thoughts?

All 16 comments

I don't think it would be wise to allow subclassing Assertions because it would blur how it's supposed to be used.

@junit-team/junit-lambda Thoughts?

which means we cannot use _JUnit 5_

This limitation does not in any way prevent you from using JUnit Jupiter (a.k.a., _JUnit 5_).

You are free to use other assertion libraries such as AssertJ, Hamcrest, Truth, etc.

You can in fact continue to use org.junit.Assert if you so desire.

See Third-party Assertion Libraries in the User Guide for details.

I don't think it would be wise to allow subclassing Assertions because it would blur how it's supposed to be used.

Based on principle, I agree.

Assertions are indeed supposed to be used via static imports.

However, if a significant number of users request that Assertions be extensible we could reconsider.

How about wrapping the assertions you need into your custom extensible type?

package a.b.c;

import org.junit.jupiter.api.Assertions;

class Assert {
  void assertEquals(...) { Assertions.assertEquals(...); }
}

Usage:

class FooTest extends a.b.c.Assert { ...

No static imports, only the assertions you need, customizable with custom assertions and only need to adopt the package of the Assert type you extend.

...not use qualified access on our 1000's of assertions...

If you're low on time, keep your unit tests running "as-is" with the Vintage engine. Write new ones with Jupiter API.

How about wrapping the assertions you need into your custom extensible type?

Not really a solution since I need to copy-paste all the delegated methods (and there are many of them) - not to mention that if there is a new or modified method on a new version I need to keep updating my class.

If you're low on time, keep your unit tests running "as-is" with the Vintage engine.

Again, not really a solution - the whole idea is to get rid of obsolete code. If all I do is use the Vintage engine why switch to JUnit 5 and not remain with 4 ?

Assertions are indeed supposed to be used via static imports.

Again, without going into a discussion, this is a legitimate decision, but we decided that the cons outweigh the pros of using static imports and therefore enforce (via _Checkstyle_) the ban on using them.

Do you also extend java.lang.System in order to use static methods like arraycopy and friends?

Again, not really a solution - the whole idea is to get rid of obsolete code.
If all I do is use the Vintage engine why switch to JUnit 5 and not remain with 4 ?

If test code is obsolete, delete it.
If test code is hard to change but fulfills a purpose, keep it. Vintage to the rescue for legacy tests.
If new test code is developed, choose the right tool to achieve your (testing) goals. Be it 4 or 5 or any other framework.

Your design decisions are fine with me. Somehow limited, but fine.

Do you also extend java.lang.System in order to use static methods like arraycopy and friends?

The example is not equivalent for a variety of reasons...

Be it 4 or 5 or any other framework.

this issue is just convenient, nothing more. If this were the only issue, it would not have prevented us from adopting version 5. For now though 4 is the choice ) - not because of this issue but rather because of several others much more problematic...

It sounds to me that perhaps the best solution, at least in the interim, would be to upgrade to JUnit 5 but to continue using JUnit 4's Assert class.

@lgoldstein WDYT?

Like I said, why would we do that if we remain bound to the JUnit 4 API(s) ? What about the extra work it would take to retro-fit the code to JUnit 5 once it catches up and provides the features that are missing from it (and exist already in JUnit 4) ...

Maybe next project - after JUnit 5 matures some more...

@lgoldstein have you considered using Assertions.assertEquals() etc. without static imports?

We're always interested in feedback on missing features. Are this and #878 the only things you're missing or is there something else?

Like I said, why would we do that if we remain bound to the JUnit 4 API(s) ? What about the extra work it would take to retro-fit the code to JUnit 5 once it catches up and provides the features that are missing from it (and exist already in JUnit 4) ...

Hmm. Apologies if I've missed something,, but the way I personally see it, from what you've explained so far, it sounds to me that you sincerely want to upgrade to JUnit 5 but you're frustrated because you can't do so fully due to various issues.

I can't talk about your other issues, but if it were me, I'd happily take a sort of incremental approach where for new tests, I'd use JUnit 5's annotations and JUnit 4's Assert, whilst continuing to run my old completely-JUnit-4-based tests on the Vintage engine. I'd then wait to see if the JUnit 5 developers decide to make Assertions instantiable, and then take a similar incremental approach to gradually migrating all uses of Assert to Assertions, before finally tackling migrating the old completely-JUnit-4-based tests to JUnit 5.

The way I see it, the effort that would be needed to migrate the new JUnit 5 tests from the old Assert to the new Assertions would be rather small compared to migrating your existing JUnit 4 tests to JUnit 5.

Again, apologies if I've missed something. I'm genuinely curious to know if my proposed solution would work for you, and if not, why so. :)

Team Decision:

Allow Assertions and Assumptions to be extended via a protected constructor.

_in progress_

This has been addressed in master in dc893654e6071c4c71631db46c870cc7030e0ac5 and will be available in JUnit 5.3 RC1.

It will of course also be available in the next SNAPSHOT build.

Unfortunately, we do not use snapshots and cannot afford to wait until such time as 5.3 is released - but thanks for listening and discussing the issue.

Was this page helpful?
0 / 5 - 0 ratings