3

I have a Java class with a main method that I invoke to occasionally run some tests. Specifically, I'm trying to come up with a solution for quickly testing various code snippets that use the AWS SDK to create/read some S3 objects. I'm not really trying to build regular unit/integration tests, and I'm not interested in mocking the S3 code. I'm trying to quickly develop/debug some code using a test framework. I found the following SO question, and the answer about using JUnit5 Jupiter's Launcher and it intrigued me: How do I run JUnit tests from inside my java application? So I read the Junit5 chapter on the Launcher API and followed the example code. I came up with something like this:

class S3ManualTest {
    public static void main(String[] args) {
        LauncherDiscoveryRequest request =
            LauncherDiscoveryRequestBuilder
                .request()
                .selectors(selectPackage("com.xyz.s3util"),
                           selectClass(S3ManualTest.class),
                           selectMethod(S3ManualTest.class, "happyPath")
                )
                .build();

        Launcher launcher = LauncherFactory.create();
        SummaryGeneratingListener listener = new SummaryGeneratingListener();

        launcher.execute(request, listener);

        TestExecutionSummary summary = listener.getSummary();
        System.out.println("# of containers found: " + summary.getContainersFoundCount());
        System.out.println("# of containers skipped: " + summary.getContainersSkippedCount());
        System.out.println("# of tests found: " + summary.getTestsFoundCount());
        System.out.println("# of tests skipped: " + summary.getTestsSkippedCount());
    }

    void happyPath() {
        assertTrue(true); // Do useful stuff here
    }
}

The launcher doesn't find any tests to run, even though I specifically selected the "happyPath" method. I have tried annotating the happyPath() method with @Test, and that seems to work, but it also has the undesired side effect that the method gets executed if I run all tests in that package, either from gradle, or from inside the IDE. Essentially, I want my test methods to be invoked with the JUnit5 framework, but only when I manually run the main method in the class. I was thinking about some custom annotations, or implementing some interface that would get picked up by the test engine, but haven't gone down that route yet. I'm guessing there's some easy way of accomplishing what I'm trying to do. Thanks.

user2337270
  • 1,183
  • 2
  • 10
  • 27
  • Have you added the Jupiter engine to the classpath? – Marc Philipp May 01 '18 at 06:15
  • The text states, when adding `@Test` to `happyPath` it works. It's our "IsTestMethod" check that doesn't let the method be executed, because it is not a test method, i.e. lacking the `@Test` annotation. Bug or feature? – Sormuras May 01 '18 at 06:51
  • @MarcPhilipp I believe it was pulled in by a transient dependency because it did show up on the classpath in my IDE. – user2337270 May 01 '18 at 07:21
  • That's a feature (not a bug): the Jupiter test engine should not execute any method not annotated with `@Test`. Otherwise, Jupiter would not know that it is responsible for executing the test method. – Sam Brannen May 01 '18 at 11:56
  • @SamBrannen I understand that's how it works. As I mentioned in my comment below, I thought that maybe explicitly pointing out the class AND the method in the selector would offer an alternative way of marking which methods to use. The fact that they still don't get picked up without the `@Test` annotation was not intuitive to me. But again, I understand that what I'm doing may not be what the framework was intended to do, so I'm not arguing about it :-) – user2337270 May 01 '18 at 16:05

1 Answers1

2

I could only find a work around: disabling the happyPath() test method by default and override it in your program like explained here: https://junit.org/junit5/docs/current/user-guide/#extensions-conditions-deactivation

@Test
@Disabled
void happyPath() {
    assertTrue(true); // Do useful stuff here
}

And in your launcher setup, deactivate the DisabledCondition:

LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder
            .request()
            .selectors(selectMethod(S3ManualTest.class, "happyPath"))
            .configurationParameter(
                 "junit.jupiter.conditions.deactivate",
                 "org.junit.*DisabledCondition")
            .build();

You may also specify a dedicated switch, if you don't want deactivate DisabledCondition for the entire run:

@Test
@EnabledIf("'true'.equals(junitConfigurationParameter.get('manual'))")
void happyPath() {
    assertTrue(true); // Do useful stuff here
}

with

LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder
        ...
        .configurationParameter("manual", "true")
        .build();

The second work-around, if applied to more then a few methods, screams for a dedicated ExecutionCondition extension. See details at https://junit.org/junit5/docs/current/user-guide/#writing-tests-conditional-execution-scripts

Sormuras
  • 8,491
  • 1
  • 38
  • 64
  • Thanks. I wish there was some way of supplying a selector that would select methods that were annotated with some custom annotation. I understand that what I'm doing isn't really what the framework was designed to do, but I find it useful certain cases, and it would be neat to be able to invoke the engine locally only for a class. I guess when I saw the `selectors()` method, I thought it was kind of an alternative to the `@Test` annotation, but that's not really what it seems to be. Your solution is good enough for what I need to do. – user2337270 May 01 '18 at 07:17
  • Do want to create an issue for this feature? Using an explicit method selector should make that selected method _relevant_ for execution. – Sormuras May 01 '18 at 07:49
  • I'm happy to create an issue. Should I do it in the github repo or do you have any other system for tracking feature request/bugs? I'm also happy to pitch in on some coding if needed. – user2337270 May 01 '18 at 16:07