Suppose I develop an extension which disallows test method names to start with an uppercase character.
public class DisallowUppercaseLetterAtBeginning implements BeforeEachCallback {
@Override
public void beforeEach(ExtensionContext context) {
char c = context.getRequiredTestMethod().getName().charAt(0);
if (Character.isUpperCase(c)) {
throw new RuntimeException("test method names should start with lowercase.");
}
}
}
Now I want to test that my extension works as expected.
@ExtendWith(DisallowUppercaseLetterAtBeginning.class)
class MyTest {
@Test
void validTest() {
}
@Test
void TestShouldNotBeCalled() {
fail("test should have failed before");
}
}
How can I write a test to verify that the attempt to execute the second method throws a RuntimeException with a specific message?
After trying the solutions in the answers and the question linked in the comments, I ended up with a solution using the JUnit Platform Launcher.
JUnit itself will not run
MyTest
because it is an inner class without@Nested
. So there are no failing tests during the build process.Update
This is not completly correct. JUnit itself would also run
MyTest
, e.g. if "Run All Tests" is started within the IDE or within a Gradle build.The reason why
MyTest
was not executed is because I used Maven and I tested it withmvn test
. Maven uses the Maven Surefire Plugin to execute tests. This plugin has a default configuration which excludes all nested classes likeMyTest
.See also this answer about "Run tests from inner classes via Maven" and the linked issues in the comments.
Another approach could be to use the facilities provided by the new JUnit 5 - Jupiter framework.
I put below the code which I tested with Java 1.8 on Eclipse Oxygen. The code suffers from a lack of elegance and conciseness but could hopefully serve as a basis to build a robust solution for your meta-testing use case.
Note that this is actually how JUnit 5 is tested, I refer you to the unit tests of the Jupiter engine on Github.
Though a little verbose, one advantage of this approach is it doesn't require mocking and execute the tests in the same JUnit container as will be used later for real unit tests.
With a bit of clean-up, a much more readable code is achievable. Again, JUnit-Jupiter sources can be a great source of inspiration.
If the extension throws an exception then there's not much a
@Test
method can do since the test runner will never reach the@Test
method. In this case, I think, you have to test the extension outside of its use in the normal test flow i.e. let the extension be the SUT. For the extension provided in your question, the test might be something like this:However, your question suggests that the above extension is only an example so, more generally; if your extension has a side effect (e.g. sets something in an addressable context, populates a System property etc) then your
@Test
method could assert that this side effect is present. For example:This approach has the benefit of side stepping the potentially awkward setup steps of: creating the
ExtensionContext
and populating it with the state required by your test but it may come at the cost of limiting the test coverage since you can really only test one outcome. And, of course, it is only feasible if the extension has a side effect which can be evaulated in a test case which uses the extension.So, in practice, I suspect you might need a combination of these approaches; for some extensions the extension can be the SUT and for others the extension can be tested by asserting against its side effect(s).
JUnit 5.4 introduced the
JUnit Platform Test Kit
which allows you to execute a test plan and inspect the results.To take a dependency on it from Gradle, it might look something like this:
And using your example, your extension test could look something like this: