• 10 hours
  • Medium

Free online content available in this course.

course.header.alt.is_video

course.header.alt.is_certifying

Got it!

Last updated on 1/4/21

Create more powerful tests using JUnit annotations

“No cameras!” 📸 Has anyone ever said this to you?

Have you ever gone into off-limits areas at a museum? 🚫 Have you taken a picture where it wasn’t permitted? How did you avoid parking in the chief curator’s parking slot? Signs, right?

Signs can save you a lot of trouble by helping you do the right thing. Java also gives special signs called annotations which help you tell your code how it should behave. They start with an @ and each has its own special meaning. 

You’ve already seen one! @Test is a JUnit 4 annotation which can be put before a method. With  @Test, JUnit will immediately know that of all the methods in that file, this one is supposed to be run as a test. It will take the name of the method and make it the name of the test.

There are many useful annotations which come with JUnit, and I’ll introduce some of these to you. They can help make your tests super powerful and save you lines of code! To use these annotations, drop them into your test class, a little like putting up a new sign in a museum.

Let’s annotate!

I bet you’re dying to see JUnit’s annotations in action! Let’s dig in!

We’re going to add a few annotations to our CalculatorTest. The test class should be named after the class under test (CUT). Since we’re testing a calculator, let’s walk through a CalculatorTest which uses the basic annotations of:  @BeforeClass,  @AfterClass,  @Before,  @After, and some special spins on the  @Test  annotations: 

public class CalculatorTest {
    private static Instant startedAt; 
    private Calculator calculatorUnderTest; 

We have added a static variable and class field to use in the example above.  Now, let's check out  @BeforeClass

@BeforeClass
public static void beforeClass() {
    //let's capture the time when the test was run 
    System.out.println("Before class");
    statedAt = Instant.now();
}

@BeforeClass will cause a method to run once before our first test. In this example, we store the time when the tests were loaded. Next is @AfterClass

@AfterClass
public static void afterClass() {
    // Not the way to do it.  Just illusrating @AfterClass
    // How long did the tests take?
    Instant endedAt = Instand.now();
    Duration duration = Duration.between(startedAt, endedAt);
    System.out.println("Tests took" + duration.toString());
}

@AfterClass marks a method to be run once after our last test has completed. This will run even if the tests fail. Here we measure how long it took to run the tests. 

Next is @Before

@Before
public void setUp() {
    // Recreate the calculator before each test
    calculatorUnderTest = new Calculator();
    System.out.println("Before Test:" + Instant.now());
}

@Before marks a method so it can be run before each @Test. Here we make sure that we’ve created a new instance of Calculator.

Now we've got  @After

@After
public void tearDown() {
    // set calculator to null after each test 
    calculatorUnderTest = null;
    System.out.println("After Test" + Instant.now());
}

@After marks a method to be run as soon as JUnit has finished running a  @Test. This is often used to clean up things done in  @Before. You’ve already seen the @Test annotation. Let’s look at some options to make testing even simpler:

As you saw, the assertion to test for an exception can be passed directly to @Test. Use the expected argument as well as the value of the exception class you expect to see being thrown.

@Test(expected=Exception.class)
public void add_returnsTheSum_ofTwoPositiveNumbers() throws Exception {
        Double expected = 3.0;
        Double sum = calculatorUnderTest.add(left:1.0, right:2.0);
        assertThat(expected,is (equalTo(sum)));
        //prentend this was from your code! 
        throw new Exception ("We expect an Exception");
}

@Test(expected=<Exception.class> ) passes some options to  @Test  which allow you to test sad paths where you expect a particular exception to be thrown. 

Let’s look at how tests can let you know if the methods they are testing suddenly become too slow:

As you saw, you can pass @Test the timeout argument with a value of the time, in milliseconds, which the test should not exceed. That way, your tests will tell you if you ever put a slow algorithm into your code!

@Test(timeout=1000)
public void add_returnsTheSum_OfTwoNegativeNumbers() throws Exception {
        Double expected = -3.0;
        Double sum = calculatorUnderTest.add(left:-1.0, right:-2.0);
        assertThat(expected, is(equalTo(sum)));
        // Let's timeout our test
        Thread.sleep(millis:2000);
}

@Test(timeout=1000)  fails the test marked with this annotation if it takes longer than 1000ms (1 second). Can you see that the test is rigged to fail?

This is what happens when you run it:

Your test has been run!
Your test has been run!

Try and match up the printed messages (e.g., before class in the right panel) with the steps in the code above. Can you see which test failed?

It's your turn now!

Check out the repository and try running these tests for yourself.

git clone https://github.com/OpenClassrooms-Student-Center/AchieveQualityThroughTestingInJava.git
git checkout p1-c5-sc2-to-sc3

Or, use your IDE to clone  https://github.com/OpenClassrooms-Student-Center/AchieveQualityThroughTestingInJava.git and check out the branch p1-c5-sc2-to-sc3.

You can now explore the examples from the screencast and try running the tests with:

mvn test

Let's recap!

  • JUnit’s annotations help you write clearer tests without unnecessary repetition.

  • Some common annotations are:

Annotation

When to use it

@Test(timeout=milliseconds)

If testing method which should not be too slow, you can force it to fail the test.

@Test(expect=<Exception>.class)

Use this annotation to test if your class throws an exception. Don’t use try/catch to test for it.

@Before

Run a method prior to each test. This is a great place to set up or to arrange a precondition for your tests.

@After

Run a method after each test. This is a great place to clean up or satisfy some post-condition.

@BeforeClass

Mark a static method so it runs before all your tests. You can use this to set up other static variables for your tests.

@AfterClass

Mark a static method as being run after all your tests. You can use this to clean up static dependencies.

Now that you know how to do unit testing, let's make it even easier by adding some effective plugins...in the next chapter!  See you there! 

Example of certificate of achievement
Example of certificate of achievement