Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dynamic container support in @TestFactory methods #813

Merged
merged 3 commits into from
May 3, 2017
Merged

Conversation

sormuras
Copy link
Member

@sormuras sormuras commented Apr 28, 2017

Overview

Addresses #695 and #604

Add dynamic container support in @testfactory methods.

https://travis-ci.org/junit-team/junit5/builds/228235319#L596 is generated by:

Stream.of("A", "B", "C")
	.map(input -> dynamicContainer("Container " + input, Stream.of(
		dynamicTest("not null", () -> assertNotNull(input)),
		dynamicContainer("properties", Stream.of(
			dynamicTest("length > 0", () -> assertTrue(input.length() > 0)),
			dynamicTest("not empty", () -> assertFalse(input.isEmpty()))
		))
	)));

I hereby agree to the terms of the JUnit Contributor License Agreement.


Definition of Done

Copy link
Member

@marcphilipp marcphilipp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this looks great overall! 👍

The fact that this did not require any changes outside of Jupiter tells me that our abstractions work, even though Node.isLeaf() feels a bit fishy.

return new DynamicContainer(displayName, StreamSupport.stream(dynamicNodes.spliterator(), false));
}

public static DynamicContainer dynamicContainer(String displayName, Stream<? extends DynamicNode> dynamicNodes) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering if we should make them use Supplier<Iterable<? extends DynamicNode>>/Supplier<Stream<? extends DynamicNode>>. Thoughts?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Every overload that makes usage of dynamicContainer more elegant is good to have.

private final DynamicContainer dynamicContainer;
private final AtomicInteger index;

DynamicContainerTestDescriptor(UniqueId uniqueId, DynamicContainer dynamicContainer, AtomicInteger index,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AtomicInteger is mutable. I think we should pass the index as an int.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Never mind, if we follow my proposal below we don't need to pass the index at all.

public JupiterEngineExecutionContext execute(JupiterEngineExecutionContext context,
DynamicTestExecutor dynamicTestExecutor) throws Exception {
TestSource source = getSource().orElseThrow(AssertionError::new);
for (DynamicNode childNode : dynamicContainer.getDynamicNodes()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think every level of the hierarchy should have separate indices starting with 1 on every level.

@@ -71,11 +74,13 @@ protected void invokeTestMethod(JupiterEngineExecutionContext context, DynamicTe
Object instance = testExtensionContext.getTestInstance();
Object testFactoryMethodResult = executableInvoker.invoke(getTestMethod(), instance, testExtensionContext,
context.getExtensionRegistry());

try (Stream<DynamicTest> dynamicTestStream = toDynamicTestStream(testFactoryMethodResult)) {
TestSource source = getSource().orElseThrow(AssertionError::new);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know this "cannot happen", but I'd be a little more comfortable with JUnitException::new.

descriptor = new DynamicTestTestDescriptor(uniqueId, test, source);
}
else {
DynamicContainer container = (DynamicContainer) node; // ClassCastException is an error.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need this comment?

return nodes;
}

@TestFactory
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is the best example for the documentation. I'd rather show some real nesting. Thoughts?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure. Any real example available?

@sbrannen
Copy link
Member

sbrannen commented Apr 28, 2017

@marcphilipp wrote:

I think this looks great overall! 👍

The fact that this did not require any changes outside of Jupiter tells me that our abstractions work, even though Node.isLeaf() feels a bit fishy.

👍

@nipafx
Copy link
Contributor

nipafx commented Apr 30, 2017

Since I opened #604, @sormuras asked me to comment on this PR. Regarding the hierarchical organization of tests, I think it fits the bill very well. 👍 The other part of #604 is that it talks about an extension point for dynamic tests (like in #371) but the discussion regarding that can happen elsewhere.

sormuras and others added 3 commits May 3, 2017 13:09
Prior to this commit only a flat collection of dynamically generated
tests was allowed as the return type of a @testfactory annotated
method. The collection entry type was set to `DynamicTest`.

This commit introduces the abstract base class `DynamicNode` and a
`DynamicContainer` class collecting node instance. @testfactory
annotated methods are now allowed to return a collection of nodes --
which can be a test or a named container of tests.
Creating a dynamic tree of tests like that gives users the ability to
better structure the generated tests.

The old behaviour, returning only instances of `DynamicTest`, is preserved.
@sormuras
Copy link
Member Author

sormuras commented May 3, 2017

Team decision: Merge this feature "as-is" and move the open documentation tasks into a new issue.

@sormuras sormuras mentioned this pull request May 3, 2017
3 tasks
@sormuras sormuras merged commit 3370ffb into master May 3, 2017
@sormuras sormuras deleted the dynamic_node branch May 3, 2017 11:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants