testng-team / testng

TestNG testing framework
https://testng.org
Apache License 2.0
1.98k stars 1.02k forks source link

Add support for record classes in data providers #2241

Open mcimadamore opened 4 years ago

mcimadamore commented 4 years ago

It would be nice if testng supported the newly added records feature, as a means to replace Object arrays in data providers. Record types [1] are simple data carriers, which can contain any data. They are better suited at modelling parameter lists than Object[] for a number of reasons:

This would enable not only test writers to write better code, but also for the testng framework to become more robust (since testng could cross-validate the record component types against the parameter types of a given test method using a data provider). Similarly, IDEs could take advantage of the added type safety and highlight mismatches between data providers and tests.

Expected behavior

record R(int x, String s);

public List<R> dataProvider() {
    return List.of(
               new R(1,"one"),
               new R(2,"two"));
}

Actual behavior

public Object[][] dataProvider() {
        return new Object[][] {
             { 1, "one" },
             { 2, "two" },
        };
    }

[1] - https://openjdk.java.net/jeps/359

juherr commented 4 years ago

@mcimadamore Did you try it? What was the issue? I think it could already work.

mcimadamore commented 4 years ago

I did not try - note that it will require changes to the testng data provider mechanism so that it will support record types natively. In other words, the above describes a possible suggestion for an enhancement to the testng framework to take advantage of some of the newer Java features.

juherr commented 4 years ago

Data providers accept Iterators and I don't see why it can't work with an iterator of records.

mcimadamore commented 4 years ago

If I'm not mistaken, the Iterator support currently goes like

@DataProvider
Iterator<Object[]> dataProvider() { ... }

While Iterator<Object[]> is slightly better than Object[][], you still have the problems described in my original issue:

The solution I've sketched uses a record - which you can think of as a named tuple - to model the Object[] part of the data provider (that is, the set of arguments to be passed to a single test method call).

So, if Person is a record like this:

record Person(int age, String name);

a data provider could return either:

Then your test can still be something like:

@Test
void m(int age, String name) { ... }

Much easier to see if the data provider agrees with the test method, and also easy for testNG to reflectively unpack the record Person into the two components (age and name) and pass those to the test method.