JUnit confusion: use 'extends TestCase' or '@Test'?

automated-tests, java, junit

Solution

The distinction is rather easy:

- extending `TestCase` is the way unit tests were written in JUnit 3 (of course it's still supported in JUnit 4)

- using the `@Test` annotation is the way introduced by JUnit 4

Generally you should choose the annotation path, unless compatibility with JUnit 3 (and/or a Java version earlier than Java 5) is needed. The new way has several advantages:

- The `@Test` annotation is more explicit and is easier to support in tools (for example it's easy to search for all tests this way)

- Multiple methods can be annotated with `@Before`/`@BeforeClass` and `@After`/`@AfterClass` providing more flexibility

- Support for `@Rule` annotations on things like `ExpectedException`

- Support for the `@Ignored` annotation

- Support for alternative test runners using `@RunWith`

To test for expected exceptions in a JUnit 3 `TestCase` you'd have to make the text explicit.

public void testMyException() {
  try {
    objectUnderTest.myMethod(EVIL_ARGUMENT);
    fail("myMethod did not throw an Exception!");
  } catch (MyException e) {
    // ok!
    // check for properties of exception here, if desired
  }
}

JUnit 5 introduced yet another API change, but still uses annotations. The new `@Test` annotation is `org.junit.jupiter.api.Test` (the "old" JUnit 4 one was `org.junit.Test`), but it works pretty much the same as the JUnit 4 one.

Problem

I've found the proper use (or at least the documentation) of JUnit very confusing. This question serves both as a future reference and as a real question. If I've understood correctly, there are two main approaches to create and run a JUnit test: Approach A (JUnit 3-style): create a class that extends TestCase, and start test methods with the word `test`. When running the class as a JUnit Test (in Eclipse), all methods starting with the word `test` are automatically run. ``` import junit.framework.TestCase; public class DummyTestA extends TestCase { public void testSum() { int a = 5; int b = 10; int result = a + b; assertEquals(15, result); } } ``` Approach B (JUnit 4-style): create a 'normal' class and prepend a `@Test` annotation to the method. Note that you do NOT have to start the method with the word `test`. ``` import org.junit.*; import static org.junit.Assert.*; public class DummyTestB { @Test public void Sum() { int a = 5; int b = 10; int result = a + b; assertEquals(15, result); } } ``` Mixing the two seems not to be a good idea, see e.g. this stackoverflow question: Now, my questions(s): - What is the preferred approach, or when would you use one instead of the other? - Approach B allows for testing for exceptions by extending the @Test annotation like in `@Test(expected = ArithmeticException.class)`. But how do you test for exceptions when using approach A? When using approach A, you can group a number of test classes in a test suite like this: `TestSuite suite = new TestSuite("All tests");` `suite.addTestSuite(DummyTestA.class);` `suite.addTestSuite(DummyTestAbis.class);` But this can't be used with approach B (since each testclass should subclass TestCase). What is the proper way to group tests for approach B? Edit: I've added the JUnit versions to both approaches

Original source

Related problems