Junit Confusion: Use 'Extends Testcase' or '@Test'

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

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.

Why don't I need to extend TestCase when writing a test class using JUnit?

Since v4 the JUnit test runner discovers tests by looking through a given path for classes which contain JUnit annotations such as @Test, @Before, @After etc.

So, a class is deemed a test case if it contains at least one public method having a JUnit annotation (though, of course, a class which has a @Before method but no @Test methods would be useless) and since JUnit discovers test cases by annotation there is no need to extend TestCase.

Prior to v3, JUnit used a class hierarchy approach so a class was deemed a test case if it implemented TestCase.

junit: no tests found

I was getting this error, too:

junit.framework.AssertionFailedError: No tests found in ...

The reason was that I forgot to specify

defaultConfig {
...
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}

After syncing the project, it found the tests. So maybe it helps someone else.

JUnit: how do you extend TestCase if the class already extends something?

You seem to be using Junit 3.x. From Junit 4.0, your test case class doesn't need to extend TestCase. It just needs to have methods annotated with @Test, @Before, @After, @BeforeClass, @AfterClass etc., as required. This would allow your test case class to extend some other class.

In our project, we run JUnit tests using Spring test runner and need to associate a couple of annotations with each test case. We address this by defining an abstract test case, associate the annotations with this abstract test case, and make every other test case extend this.

@RunWith(SpringJunit4TestRunner.class)
@ContextConfiguration(location={})
public class AbstractTestCase
{

}

public class ConcreteTestCase extends AbstractTestCase
{
@Before
public void setUp()
{
// Some set up before each test.
}

@Test
public void test1()
{
// Some test
}

@Test
public void test2()
{
// Some other test
}

@After
public void tearDown()
{
// Some tear down process after each test.
}

}

JUnit unable to find tests in Eclipse

I never found out the real cause of this issue but an upgrade to Eclipse 3.6 finally solved it.

Why Junit still allow a class extend TestCase to use the annotation @Test in it?

The TestCase class is from Junit 3 and should not be used in Junit 4 + classes.

If you extend TestCase, and use the Junit 3 Test runners then your test method names need to start with the word "test". (Junit 3 test runners use Java reflection to find and invoke all methods that start with the word "test")

Relying on TestClass hindered test class designs because you were forced to extend that class which made somethings hard to test. There also wasn't anything equivalent to Junit4's @BeforeClass or @AfterClass which meant you had to do all the more complicated multi-test fixture set up and tear down yourself.

To run many Junit4 test classes at once as a Test Suite, you can create a new empty class with the @RunWith and @SuiteClasses annotations as shown below:

import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;

@RunWith(Suite.class)
@SuiteClasses(
{
TestClassA.class,
TestClassB.class

}
)

public class MyTestSuite{

}

Subclass TestCase and use JUnit 4 annotations

Try this annotation at your test class.

@RunWith(JUnit4.class)
public class MyTestCase extends MapInterfaceTest {...}

This should force Junit to use Junit4 not Junit3 in the execution. Maybe that works for your Testcase.

However, JUnit4 will not pick up old-style "test*" test methods, as it relies on @Test annotations. If the class you're extending doesn't have these annotations and you can't add them directly, you can override the tests in order to add the annotations in the subclass, like so:

@Test
@Override
public void testFoo()
{
super.testFoo();
}


Related Topics



Leave a reply



Submit