Paul A. Hoadley
Paul A. Hoadley

Reputation: 1545

How can I run particular sets of JUnit tests under specific circumstances?

I have a Java codebase that is developed exclusively in Eclipse. There are a set of JUnit4 tests that can be divided into two mutually exclusive subsets based on when they are expected to run:

  1. "Standard" tests should run when a developer right-clicks the test class (or containing project) and selects Run As > JUnit Test. Nothing unusual here—this is exactly how JUnit works in Eclipse.
  2. "Runtime" tests should only run when called programmatically from within the application when it is started up in a specific state.

The two types of tests might sit adjacent to each other in the same Java package. (Ideally we could intermix them in the same class, though that's not a hard requirement.)

My first solution was to annotate the "Runtime" test classes with a new @TestOnLaunch annotation. The application is able to find these classes, and was running the tests contained in them (annotated with @Test) using JUnitCore.run(Class<?>...). However, these tests leak into the "Standard" scenario above, because the Eclipse test runner will run any method annotated with @Test, regardless of the intent of my custom class annotation.

Next I tried moving the @TestOnLaunch annotation to the method level. This prevents the "leakage" of the "Runtime" tests into the "Standard" scenario, but now I can't seem to get JUnitCore to run those test methods. run.(Request) with a Request targeted at the correct class and method, for example, fails with "No runnable methods", presumably because it can't find the @Test annotation (because it's not there).

I'm very interested to know if there's a "JUnit way" of solving this kind of problem. Presumably I could write my own Runner (to run methods annotated with @TestOnLaunch)—is this the right approach? If so, how do I then kick off the testing programmatically with a bunch of classes, analogous to calling JUnitCore.run(Class<?>...)?

Upvotes: 2

Views: 2921

Answers (2)

Yugang Zhou
Yugang Zhou

Reputation: 7283

If you don't mix the two type test method in the same test class, this below may help:

http://johanneslink.net/projects/cpsuite.jsp

You can use the filter feature to setup two test suite.

I setup three test suites in my project by defining several mark interfaces:

UnitTests, IntegrationTests, DeploySmokeTests, AcceptanceTests

And three test suites:

@RunWith(ClasspathSuite.class)
@SuiteTypes({UnitTests.class, IntegrationTests.class})
public class CommitTestSuite {}

@RunWith(ClasspathSuite.class)
@SuiteTypes({DeploySmokeTests.class})
public class DeploySmokeTestSuite {}

@RunWith(ClasspathSuite.class)
@SuiteTypes({AcceptanceTests.class})
public class AcceptanceTestSuite {}

Now you could achieve your goal by running specific test suite. An alternative solution is using junit category:

@Category(IntegrationTests.class)
public class SomeTest {

    @Test
    public void test1() {
        ...
    }

    @Test
    public void test2() {
        ....
    }
}

@RunWith(Categories.class)
@IncludeCategory(UnitTests.class, IntegrationTests.class)
@SuiteClasses( { //all test classes })
public class CommitTestSuite {}

As I said if you mix differenct type test method in one test class, the first one can't help you, but by using the seconde solution you could annotate your category interface on test method (I annotated it on test class in the example above). But if you choose the second solution, you have to maintain your test suite every time you add a new test class.

Upvotes: 3

First, you should reevaluate why you're using JUnit tests at runtime; that seems like an odd choice for a problem that probably has a better solution.

However, you should look at using a Filter to determine which tests to run, possibly in conjunction with a custom annotation.

Upvotes: 2

Related Questions