JUnit Jupiter Annotations, Chapter 2

Overview

In part 1 I introduced you to JUnit 5 annotations:

  • @DisplayName
  • @Test

In this chapter, I’ll show you two more annotations:

  • @Disabled
  • @Nested

With code examples for both, and a video where I write code using these annotations.

You can download the complete sample application from GitHub if you like.

Let’s get started!

The Class Under Test

Before diving into the meat of this, let me show you the class under test. It’s called Echo, and it’s very simple (so as not to get in the way of the lesson):

public class Echo {
  public String echo(String stringToEcho) {
    return stringToEcho;
  }

  public Integer echo(Integer intToEcho) {
    return intToEcho;
  }

}

The class is pretty simple: its contract stipulates that it echoes whatever is passed, unchanged.

In true Test-Driven Development (TDD) style, you’ll write the implementation after you write the unit tests.

@Disabled

@Test
@Disabled
@DisplayName("A disabled test")
void testNotRun() {
  // This method will not run
}

Use this annotation to tell the JUnit platform not to run this test method. Notice that the method is annotated with the @Test annotation. Normally, JUnit would execute this method at the appropriate point in the test lifecycle, but annotating the method with @Disabled tells JUnit not to run it.

Why not just remove the @Test annotation? It might be good for documentation purposes to leave it annotated with @Test so you know it was a test method, or maybe you just want to temporarily disable the method.

@Nested

This is a super cool new feature of JUnit 5 that allows you to create nested (inner) classes that keep groups of tests together in the same main test class, but separate from the other test methods in that class.

In the case of the Echo class, both methods are called echo, so you need some way of distinguishing which echo overload you’re testing. You could do something like this:

@Test
public void testEcho_String() {
.
.
}

@Test
public void testEcho_Integer() {
.
.
}

And that would work just fine. But JUnit 5 and the Jupiter API give you the @Nested annotation. So let’s use it!

 
  @Nested
  public class StringEchoTest {

    @Test
    public void testEcho() {

      classUnderTest = new Echo();

      String expectedString = "This is a test";

      assertAll("String version of echo() method",
          // equals() should match, 
          /// but that is not good enough
          () -> assertEquals(expectedString, 
                 classUnderTest.echo(expectedString)),
          // hash codes should match, 
          /// but still not quite good enough
          () -> assertEquals(expectedString.hashCode(), 
                 classUnderTest.echo(expectedString).hashCode()),
          // This should do the trick
          () -> assertEquals(
              System.identityHashCode(expectedString),
               System.identityHashCode(
                classUnderTest.echo(expectedString))));
    }

  }

  @Nested
  public class IntegerEchoTest {

    @Test
    public void testEcho() {

      classUnderTest = new Echo();

      Integer expectedInteger = Integer.valueOf(238);

      assertAll("String version of echo() method",
          () -> assertEquals(expectedInteger, 
                 classUnderTest.echo(expectedInteger)),
          () -> assertEquals(expectedInteger.hashCode(), 
                 classUnderTest.echo(expectedInteger).hashCode()),
          () -> assertEquals(
              System.identityHashCode(expectedInteger),
                System.identityHashCode(
                 classUnderTest.echo(expectedInteger))));
    }
  }

Video

In the video below, I’ll go over these annotations in detail, and you can watch me explain the code as I write it.

Conclusion

In this article, I showed you some of the annotations from the JUnit Jupiter API you’re most likely to use. But there is a LOT more to JUnit than the Annotations.

Be sure to follow along with this series here on my blog, and the accompanying videos on my YouTube channel.

To learn more about the annotations provided by the JUnit Jupiter API visit the JUnit 5 User’s Guide.

Check out my IBM developerWorks JUnit 5 Tutorial Series:

Check out the first post in this series here.

 

Advertisement

JUnit Jupiter Annotations: Chapter 1

Overview

In order to run JUnit tests, you need to tell the JUnit Platform about your test classes: which methods are test methods, which methods are part of the test method lifecycle, whether to use extensions, and so on.

You do this through annotations, which are metadata about how to run your tests.

You can download the code from GitHub if you like:

https://github.com/makotogo/HelloJUnit5

In this post, I’ll cover the two annotations you’re likely to use with JUnit, along with examples of each.

@Test

@Test
@DisplayName("When numbers are > 0")
public void testAdd() {
  // Unit test code here
}

Use this annotation to tell the JUnit platform that the method is a test method. This means it will be invoked at the appropriate point in the lifecycle, complete with all the bells and whistles.

Every method you want to run as a test method needs to be annotated with the @Test annotation.

@DisplayName

@DisplayName("Testing using JUnit 5")
public class JUnit5AppTest {
.
.
  @Test   
  @DisplayName("When numbers are > 0")   
  public void testAdd() {     
    // Unit test code here 
  }
.
.
}

By default, the name displayed for a test class or method is the name of the class or method, respectively. The @DisplayName annotation tells JUnit to use the specified name instead.

Check it out: compare the following examples, first without the annotation, then with it. (Both are from the JUnit View in Eclipse)

Without the @DisplayName annotation:

 WithoutDisplayName

And with the @DisplayName annotation:

WithDisplayName

In this simple example, you can see already that the report is cleaner. But when there are several test methods, the value of @DisplayName gets even clearer:

DisplayNameLargerTest

Video

In the video below, I’ll go over the annotations in detail, and you can watch me explain the code as I write it.

Conclusion

In this article, I showed you two of the annotations from the JUnit Jupiter API you’ll definitely want to use. Stay tuned for more in this series, where I’ll show you more annotations from the JUnit Jupiter API.

Be sure to follow along with this series here on my blog, and the accompanying videos on my YouTube channel.

To learn more about the annotations provided by the JUnit Jupiter API visit the JUnit 5 User’s Guide.

Check out my IBM developerWorks JUnit 5 Tutorial Series:

JUnit Jupiter Assertions: Setup

Hey everybody!

The Assertions class of the JUnit Jupiter API is the GO-TO for testing your code. After all, how do you check a condition without an Assertion?

I’m doing a multi-part series on the Assertions API on my YouTube channel (Makoto TV), so make sure and check it out.

In Part 0, I show you how to get the code that accompanies all of the videos, and get your Eclipse workspace setup.

 

Make sure and check it out.

And thanks for reading!

–jsp

Java News and Code, Episode 14

Welcome

Welcome to Java News and Code, where I tell you about interesting goings-on in the world of IT in general, and Java in particular.

And there’s always code.

On This Episode:

  • Oracle wants to open source Java EE
  • Android Oreo is here
  • Code: A custom Maven archetype for JUnit 5

TLDR;

TODO: VIDEO HERE

Oracle wants to open source Java EE

On August 17th, Oracle Software Evangelist David Delabassee said Oracle wants to open up Java EE.

The announcement on the Oracle Blog says that as the summer ends, releases wrap up, and JavaOne 2017 approaches, this is an “…opportunity to rethink how Java EE is developed in order to make it more agile and responsive to changing industry and technology demands.”

As InfoQ points out, Oracle has been criticized regarding how it’s steered Java EE in the past, which has led to efforts such as the Java EE Guardians, a group “…committed to moving the Java EE platform forward through active community participation and advocacy.”

Java EE Guardians’ members include James Gosling, the Father of Java, and Cameron McKenzie, editor-in-chief of the Server side. It’s not clear what qualifies someone to be a Java EE Guardian, but qualifications span the spectrum from Father of Java, to Java Blogger, to this Java EE Guardian, whose qualifications include Student.

Reaction outside Oracle seems to be positive, with IBM’s Ian Robinson weighing in on the WASDev blog saying, “…we are delighted that Java EE is moving with the times to an open foundation for its ongoing development following the completion of Java EE 8 this year.”

So who will take over Java EE?

Responses to an unofficial Twitter poll by Java EE Guardian Reza  Rahman asking that question seem overwhelmingly in favor of handing stewardship of the platform over to Apache.

So what does this mean for Java EE? It depends on whom you ask, but given the popularity and prevalence of the platform, I’m sure it will stay in good hands.

Be sure to check out the show notes page, where you can find more information on this story, and everything I talk about in this episode.

Android Oreo is here

We’ve been following Android O for some time now here at Java News and Code, and at long last, Android O, named Oreo, has been released!

For users, Android Oreo has a bunch of new features, some of which are immediately obvious like picture in picture, and per-app notification options.

Other changes like background limits, are designed to improve device responsiveness and extend battery life.

For developers, things get more complicated. The optimizations and improvements come at a cost, which will be paid on the development side. And rightly so.

What does that mean for developers like me, who have apps in the Play Store?

For now, probably not much. Oreo is not even showing up on the Android Dashboard as of today, but of course, it’s only a matter of time.

Android Marshmallow has the single greatest share of installations, and it was released in October of 2015, coming on two years. So we have time.

But as developers we need to be ready. Fortunately, there is information available already to help us get ahead of this, like this video on the Android Developers YouTube channel.

This release is huge, there’s no denying it. And in my opinion totally worth it. Check out this article at Gizmodo, that lays out 11 cool new features in Oreo.

Be sure to check out the show notes page, where you can find more information on this story, and everything I talk about in this episode.

Code: A custom Maven archetype for JUnit 5

On August 24th, JUnit 5, Release Candidate 3 was released.

This release, which signals the impending General Availability (GA) Release, includes the usual spate of bug fixes, breaking changes, and new features.

The GA release is scheduled for September 6th, according to the milestones page.

A Maven archetype is a special type of Maven project that is used to generate other Maven projects. If you’ve ever used the New Project wizard in Eclipse to create a Maven project, chances are you’ve used the maven-quick-start archetype. Guess what? That’s a Maven archetype!

For this episode’s code talk through, I want to show you how to create a Maven archetype that you can use to create new projects that will come with JUnit 5 dependencies and boilerplate code.

The source code for the archetype is available in GitHub. And in this episode I want to do a quick walk through of the code for a Maven archetype, how it’s structured, and how to use it to generate a new project.

Let’s get started.

First, clone the code from GitHub. Open a Terminal window, navigate to the directory where you want the code to land and execute the git clone command:

git clone https://github.com/makotogo/JUnitJupiterArchetype

Next, import the code into Eclipse.

With the code in Eclipse, let’s take a quick tour. Expand all of the nodes in the source tree. Open the src/main/resources/META-INF/maven/archetype-metadata.xml file, which tells the archetype generator what source files, test  source files, resources and so forth you want to be included in new projects generated from the archetype.

A Maven archetype project is itself a Maven project, so there are two POM files to deal with:

The one that controls the archetype project itself, located in the project root:

  4.0.0
  com.makotojava.learn
  junit-jupiter-archetype
  0.9.1
  Archetype - jupiterArchetype
  http://maven.apache.org
  jar

And the POM file that will be included in any projects created from the archetype, src/main/resources/archetype-resources/pom.xml.

The archetype project also includes boilerplate code like this:

package $package;

import static org.junit.jupiter.api.Assertions.assertAll;
import static org.junit.jupiter.api.Assertions.assertEquals;

import org.apache.log4j.Logger;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.platform.runner.JUnitPlatform;
import org.junit.runner.RunWith;

/**
 * Unit test for simple App.
 */
@RunWith(JUnitPlatform.class)
public class AppTest {
  
  private static final Logger log = Logger.getLogger(AppTest.class);

  private App classUnderTest;

  @BeforeEach
  void setUp() {
    classUnderTest = new App();
  }

  @Test
  @DisplayName("assertAll on a bunch of Strings should succeed.")
  public void doIt() {
    log.info("Testing doIt()...");
    assertAll(
        () -> assertEquals("String", classUnderTest.doIt("String")),
        () -> assertEquals("StringToo", classUnderTest.doIt("StringToo")),
        () -> assertEquals("String2", classUnderTest.doIt("String2")),
        () -> assertEquals("StringAlso", classUnderTest.doIt("StringAlso")));
  }

}

To use the archetype to create new projects, you first have to build the archetype project itself. Like I said, it’s a Maven project, so to build it go to Run As > Maven Project and specify the install and archetype:crawl goals to install it in your local Maven repository, and update your local archetype catalog, respectively.

Next, make sure the archetype is included in your local Maven archetype catalog, which is located in the repository root in a file called archetype-catalog.xml. And there it is.

Screen Shot 2017-08-28 at 12.07.50 PM

Now, I can use that to create projects in Eclipse. First, make sure Eclipse recognizes the local maven catalog. Under Preferences > Maven > Archectypes, click on Add Local Catalog. Browse or enter the path to your local archetype-catalog.xml file, give it a description you’ll recognize later, click Ok. Then Click Apply and close.

To create a new project based on the new archetype, go to File > New Project > Maven Project. Click Next. Click Next again. Select the archetype in the list, and complete the wizard.

Screenshot 2017-08-28 12.14.44

When the wizard completes, you now have a new project based on your custom archetype!

How cool is that?

For a detailed walkthrough of this, check out this video.

Fini

Well, that’s it for today’s episode. Be sure to check out the show notes page, where you can find more information on this story, and everything I talk about in this episode.

Thanks for watching Java News and Code (and reading this post).

I’ll see you next time.

–jsp

Injecting Parameters into JUnit 5 Unit Tests (@ Baeldung.com)

Check out my first (hopefully of many!) post at Baeldung.

The post is called: Inject Parameters into JUnit Jupiter Unit Tests

If you’ve been wanting to make the move to JUnit 5, now is the time! JUnit 5 Release Candidate 2 is out (as of this writing), and the final release is getting closer every day!

I love writing about software testing. I believe as developers we don’t pay enough attention to unit testing (myself included), so it’s important to me to get the word out: unit testing is important!

There, I said it.

–jsp

p.s., Keep checking back here for more information on JUnit, including tutorials, like this one I wrote for IBM developerWorks.

The JUnit Jupiter API

Greetings to all. There has never been a better time to dive into JUnit 5 and the JUnit Jupiter API.

Why? Because JUnit is growing ever nearer to a GA release. On July 4th, 2017 JUnit 5 Milestone 5 was released.

So what does that mean for you? Well, if you have wanted to dive into JUnit 5, but have been reluctant, let me guide you.

In my JUnit 5 Tutorial series at IBM developerWorks, you can read all about the JUnit Jupiter API in Part 1, and in Part 2 move on to some of the more advanced features of JUnit.

Very exciting. Yes?

Start here. And enjoy!

–jsp

Check out the video for Part 1 below:

JUnit 5 Demo – Maven

Greetings, JUnit fans!

Because tool vendors, in order to get the most out of JUnit, used
internal APIs, this caused JUnit maintainers some headaches in moving
JUnit forward, as explained in this article by Nicolai
Parlog.

JUnit 5 breaks new ground mainly because of its
built in separation of concerns into two areas:

  1. An API used to write tests
  2. A mechanism to discover and run those tests.

For that reason, JUnit 5 was split into three sub
projects:

  • JUnit Jupiter – the API to write tests
  • JUnit Platform – the API to discover and run tests
  • JUnit Vintage – provide backward compatibility to run JUnit 3 and 4 tests.

For this post, I’ll use Eclipse, but you should be able to use any IDE you like.

The code for this post is available from Github at this link: https://github.com/makotogo/JUnit5MavenDemo

I’ll clone the code first:

$ cd ~/home/projects/learn
$ git clone https://github.com/makotogo/JUnit5MavenDemo

Next, I’ll start Eclipse, and import the code.

  1. Go to File > Import…
  2. Choose Maven > Existing Maven Projects.
  3. Navigate to the folder where you cloned the github repo (in my case it’s ~/home/projects/learn/JUnit5MavenDemo).
  4. Click Finish.

The class under test is very simple:

package com.makotojava.learn.junit5.demo;

public class App {
  public long add(long[] operands) {
    // Compute the sum
    long ret = 0;
    if (operands == null) {
      throw new IllegalArgumentException("Operands argument cannot be null");
    }
    if (operands.length == 0) {
      throw new IllegalArgumentException("Operands argument cannot be empty");
    }
    for (long operand : operands) {
      ret += operand;
    }
    return ret;
  }
}

Next, let’s look at the JUnit5App class. I’ll show it in pieces and explain the pieces as I go. Please refer to the full code listing in your IDE if you need more context.

package com.makotojava.learn.junit5.demo;

import static org.junit.jupiter.api.Assertions.assertAll;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.platform.runner.JUnitPlatform;
import org.junit.runner.RunWith;

@RunWith(JUnitPlatform.class)
@DisplayName("Testing using JUnit 5")
public class JUnit5AppTest {
  private App classUnderTest;
  @BeforeAll
  public static void init() {
    // Do something before ANY test is run in this class
  }

  @AfterAll
  public static void done() {
    // Do something after ALL tests in this class are run
  }

  @BeforeEach
  public void setUp() throws Exception {
    classUnderTest = new App();
  }

  @AfterEach
  public void tearDown() throws Exception {
    classUnderTest = null;
  }

Notice the JUnit package names all begin with org.junit.jupiter.api. The JUnit package names have changed.

Next notice the @RunWith annotation and its JUnitPlatform.class argument. This allows tests written using JUnit Jupiter to run with a tool (like Eclipse) that does not yet natively support JUnit 5.

There is also the @DisplayName annotation, which tells JUnit to use the String argument (e.g., “Testing using JUnit 5”) rather than the default, which is the fully qualified test class name.

Then there are these annotations:

  1. BeforeAll – tells JUnit to run this method once before all test methods have run.
  2. BeforeEach – tells JUnit to run this method before each test method.
  3. AfterEach – tells JUnit to run this method after each test method.
  4. AfterAll – tells JUnit to run this method once after all test methods have run.

Next, let’s look at the testAdd() method:

  @Test
  @DisplayName("When numbers are > 0")
  public void testAdd() {
    assertAll(
        () -> {
          //
          // Test #1
          long[] numbersToSum = { 1, 2, 3, 4 };
          long expectedSum = 10;
          long actualSum = classUnderTest.add(numbersToSum);
          assertEquals(expectedSum, actualSum);
        },
        () -> {
          //
          // Test #2
          long[] numbersToSum = new long[] { 20, 934, 110 };
          long expectedSum = 1064;
          long actualSum = classUnderTest.add(numbersToSum);
          assertEquals(expectedSum, actualSum);
        },
        () -> {
          //
          // Test #3
          long[] numbersToSum = new long[] { 2, 4, 6 };
          long expectedSum = 12;
          long actualSum = classUnderTest.add(numbersToSum);
          assertEquals(expectedSum, actualSum);
        });
  }

First, we tell JUnit that this is a test method by annotating it with the @Test annotation.

Next, notice the assertAll() method. This actually runs three separate tests, each of which calls assertEquals to verify the actual result matches the expected result. No big deal, right? Well, if you’ve used JUnit 4, you know that if the first of these assertEquals() calls fails then the next two are simply not run. This is not the case with assertAll. All of the statements within the lambda are run, and the results are reported as a group.

Finally, I want to point out a new JUnit 5 annotation: @Nested. Take a look at this code from JUnit5AppTest.java:

  @Nested
  @DisplayName("When numbers to add are < 0")
  class NegativeNumbersTest {

    private App classUnderTest;

    @BeforeEach
    public void setUp() throws Exception {
      classUnderTest = new App();
    }

    @AfterEach
    public void tearDown() throws Exception {
      classUnderTest = null;
    }

    @Test
    @DisplayName("Three tests with numbers  {
            //
            // Test #1
            long[] numbersToSum = { -1, -2, -3, -4 };
            long expectedSum = -10;
            long actualSum = classUnderTest.add(numbersToSum);
            assertEquals(expectedSum, actualSum);
          },
          () -> {
            //
            // Test #2
            long[] numbersToSum = { -20, -934, -110 };
            long expectedSum = -1064;
            long actualSum = classUnderTest.add(numbersToSum);
            assertEquals(expectedSum, actualSum);
          },
          () -> {
            //
            // Test #3
            long[] numbersToSum = new long[] { -2, -4, -6 };
            long expectedSum = -12;
            long actualSum = classUnderTest.add(numbersToSum);
            assertEquals(expectedSum, actualSum);
          });
    }
  }

This annotation lets us create an inner test class within the main test class. This keeps the code more structured and orderly, while keeping code together that tests the same class under test.

The @DisplayName annotation helps as well, and the results of any tests run in the @Nested class are reported “indented” relative to the main test class.

The nesting can be arbitrary also. So you can create @Nested classes within @Nested classes (within @Nested classes, and so forth) to an arbitrary level of nesting, as you see fit, and as makes sense for what you’re trying to test.

One last thing I want to point out about @Nested classes: they may each have their own @BeforeEach and @AfterEach lifecycle methods. So if you need to do special initialization, for example, you can do that outside of the main class’ @BeforeEach and @AfterEach callbacks (which still run, by the way, so keep that in mind). Because of the way the @Nested inner classes are created, they may NOT have their own @BeforeAll and @AfterAll lifecycle callbacks. Sorry.

I hope you enjoyed this brief look at JUnit 5. Please check out the video below on my YouTube channel for a more complete look at the code.

Thanks for reading!

–jsp