Inheriting test methods and @BeforeEach / @AfterEach methods works just fine. I even have a project that provides interfaces with default test methods. Just implementing these interfaces gives classes all of the test methods. If you override methods, you have to repeat the annotation though. I actually use that to "remove" test methods - I override them and omit the @Test annotation.

For the parameterized test, that can be really easy if the number of instances is fixed and limited (if not, dynamic tests are a better option). You can create turn the current parameterized test into an abstract base class; you can even nest it in another class. Then for each set of parameters you use an @Nested sub class that fills in the parameters in the call to its super constructor.

In the case of FTPSClientTest, the contents of the class could be moved to a nested base class:

class FTPSClientTest {

    // statics minus testConstructorData can remain
    // testConstructorData can be removed

    abstract static class AbstractFTPSClientTest extends AbstractFtpsTest {
        // non-static contents moved here, including the constructor
    }

    @Nested
    class EndpointCheckingEnabledTest extends AbstractFTPSClient {

        EndpointCheckingEnabledTest() {
            super(true);
        }
    }

    @Nested
    class EndpointCheckingDisabledTest extends AbstractFTPSClient {

        EndpointCheckingDisabledTest() {
            super(false);
        }
    }
}


Rob

On 29/02/2024 23:19, Alex Herbert wrote:
Use of abstract classes does work in JUnit 5. I've written a lot of JUnit 5
tests that use abstract test classes which define the
@ParameterizedTest/@Test fixtures and then concrete child classes that are
run by the framework. It is supported but IIRC it is not recommended in the
JUnit 5 documentation. It has been a while since I looked to see
what alternatives are provided.

IMO the use of an abstract base class that has all the tests is still a
useful pattern. It is used in Commons Collections for the Bloom filter
package to test that implementations of the BloomFilter interfaces all
provide the required functionality. A more convoluted abstract test class
structure is used in Commons Statistics in the distribution and descriptive
packages. These abstract classes define methods to test interface
implementations. The child classes then provide instances of the interface
to test with standard data, and can provide custom data to test them with.
I do not think it is as configurable to have a single class with
@ParameterizedTest methods to test lots of different implementations. It
requires a very large method to stream all the different instances to test
and their data. This pattern is used in Commons RNG to test instances of a
random generator interface, or distribution samplers.

A quick browse of the API finds @TestTemplate which requires registering
providers and a lot more setup. Note that @ParameterizedTest is a built-in
specialization of @TestTemplate. So this is a JUnit5 way to create more
configurable tests which provide combinations of parameters for the test.

I found that using an abstract class I was able to create a test framework
that tested what was required and allowed testing of each implementation
individually. So I could do what I wanted. However I cannot state if it
would be better with @TestTemplate or some other JUnit 5 way to achieve the
same result. I remember trying a few other options but cannot remember why
I gave up and resorted to the abstract class pattern.

Note that it would be better to have VFS on JUnit 5 using abstract classes
than on JUnit 3 or 4. I would try and upgrade one test and see if it works.

Alex


On Thu, 29 Feb 2024 at 20:43, Gary Gregory <garydgreg...@gmail.com> wrote:

Thank you for digging into this Eric.

Another component to consider for JUnit 5 migration is Commons VFS. This
one is challenging due to some similar JUnit 3 and 4 heritage issues.

It is possible that between Net and VFS, what we need are custom JUnit
extensions. I had started a Commons Testing repository a long time ago but
never got far with adding what at the time were JUnit 4 rules.

I too find some of the JUnit 5 changes baffling but that's what we got...
unless we want to switch to TextNG or some other test framework which would
be a big change.

Gary


On Thu, Feb 29, 2024, 3:13 PM Elric V <elri...@melnib.one> wrote:

Hi folks,

I recently made some changes to commons-cli to move it from JUnit 4 to
JUnit 5. This was mostly straightforward, and I think it went pretty
well.

Currently looking into doing the same for commons-net, but there are a
couple of tricky tests that probably require some up front discussion,
mostly JUnit 3 style tests, and one tricky JUnit 4 Parameterized Test.

In previous versions, test classes could be extended and their test
methods would be executed as part of the child class' execution. This
was true for testt methods annotated with JUnit 4's @Test, or JUnit 3's
test-prefix naming convention.

Unfortunately, this is no longer the case in JUnit 5. I think this is a
poor design decision on their part, as it makes it significantly harder
to move to JUnit 5, and it makes certain types of tests just plain
difficult. There is some discussion about this in the JUnit community
[1], but I can't predict whether this will ever be resolved in a way to
makes commons-net's upgrade any easier.

One of those cases is AbstractFTPParseTest and its children. This
abstract base class has 11 concrete test classes. I'm struggling to see
a minimally invasive way to migrate these to JUnit 5. I'm loath to use a
heavy handed approach there.

A second tricky case is FTPSClientTest, which is a Parameterized test of
a form that no longer exists in JUnit 5. It basically creates two
instances of a test class with a boolean flag (once true, once false).

JUnit 5's @ParameterizedTest annotation operates on the **test method**
level, not on the class level, which I think would make the test case
slower and harded to read.

An alternative approach would be to use Dynamic Tests, which basically
generate test cases programmatically, but again, that makes grokking the
test a lot more difficult as it requires a greater understanding of
JUnit's features.

Any insights into this would be greatly appreciated.

Best,

Elric

[1] https://github.com/junit-team/junit5/issues/960

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org
For additional commands, e-mail: dev-h...@commons.apache.org






---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org
For additional commands, e-mail: dev-h...@commons.apache.org

Reply via email to