-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Closed
Description
@TestFactorys and DynamicTests provide API to implement multiple test probes that will become individual tests. They're centered around the idea that one would create test fixtures as instances of types and provide API to then define the naming of the test and the actual assertion:
class MyTests
@TestFactory
Stream<DynamicTest> foo() {
var fixture = Stream.of(new Foo(1, 1, 2), new Foo(2, 3, 5));
return DynamicTest.stream(fixture, it -> assertThat(it.left() + it.right()).isEqualTo(it.result()));
}
record Foo(int left, int right, int result) implements Named<Foo> {
@Override
public String getName() {
return left + " + " + right + " = " + result;
}
@Override
public Foo getPayload() {
return this;
}
}
}There are a few things to note here:
- We need to implement
getPayload()to return the instance itself to satisfyNamedalthough that method doesn't play into the signature ofDynamicTest.stream(…)as the elements of the stream are handed into the callable. - It would be nice if we were able to colocate the assertion callback with the fixture type so that the implementation of the test factory would only have to return a stream of fixtures.
Assuming an extension of Named looking like this existed:
interface NamedExecutable<T extends NamedExecutable<T>> extends Named<T>, Executable {
@Override
public default T getPayload() {
return (T) this;
}
}a bit of syntactical sugar on DynamicTest:
@SafeVarargs
public static <T extends NamedExecutable<T>> Stream<DynamicTest> stream(
NamedExecutable<T>... inputGenerator) {
return stream(Arrays.stream(inputGenerator));
}
public static <T extends NamedExecutable<T>> Stream<DynamicTest> stream(
Stream<? extends NamedExecutable<T>> inputGenerator) {
Preconditions.notNull(inputGenerator, "inputGenerator must not be null");
return DynamicTest.stream(inputGenerator, it -> it.execute());
}Would allow us to reduce the very first code sample to:
public class DummyTest {
@TestFactory
Stream<DynamicTest> foo() {
return DynamicTest.stream(new AdderTest(1, 1, 2), new AdderTest(2, 3, 5));
}
record AdderTest(int left, int right, int result) implements NamedExecutable<AdderTest> {
@Override
public String getName() {
return left + " + " + right + " = " + result;
}
@Override
public void execute() throws Throwable {
assertThat(left + right).isEqualTo(result);
}
}
}This allows to define parameterize test fixtures nicely and colocate the assertions within a type and the test factory method's responsibility is reduced to set up the individual probes.
sormuras and reneleonhardt