Core Java

JUnit in a Nutshell: Hello World

JUnit seems to be the most popular testing tool for developers within the Java world. So it is no wonder that there have been written some good books about this topic. But by earning a living as consultant I still meet quite often programmers, who at most have a vague understanding of the tool and its proper usage.

Hence I had the idea to write a couple of posts that introduce the essential techniques. The intention is to provide a reasonable starting point, but avoid daunting information flooding à la xUnit Test Patterns1. Instead there will be pointers to in depth articles, book chapters or dissenting opinions for further reading whenever suitable.

Despite the existence of other articles on the subject the approach taken in this mini-series might be appropriate to help one or two developers to warm to to the world of JUnit testing – which would make the effort worthwhile.

Why bother?

Writing high quality software is a difficult undertaking. As for many other advocates of agile approaches extensive upfront-planning did not work out well for me. But for all that methodology I experienced the biggest advancement when we began to use consequently JUnit with TDD. And indeed, empirical studies seem to confirm my perception that this practice improves quality, as an infoQ article states2.

However JUnit testing is not as trivial as it might look. A fatal mistake we made at the beginning was to treat test classes as second rated citizens. Gradually we realized that a test is much more than a simple verification machine and – if not written with care – it can be a pain in the ass regarding maintenance and progression3.

Nowadays I tend to see a test case more as an accompanying specification of the unit under test. Quite similar to the specs of a workpiece like a cogwheel, that tells QA what key figures such a unit have to met. But due to the nature of software no one but the developer is apt to write such low level specs. By doing so automated tests become an important source of information about the intented behavior of a unit. And one that does not become outdated as easily as documentation…

Getting Started

A journey of a thousand miles begins with a single step
Lao Tzu

Let us assume we have to write a simple number range counter that delivers a certain amount of consecutive integers, starting from a given value. Following the metaphor of the accompanying specification we could begin with the following code:

public class NumberRangeCounterTest {
}

The test class expresses the intent to develop a unit NumberRangeCounter, which Meszaros would denote as system under test (SUT). And following a common naming pattern the unit’s name is complemented by the postfix Test.

That is all well and good, but the impatient may wonder: What is the next step? What should be tested first? And – how do I create an executable test anyway?

There are various ways to incorporate JUnit. If you work with the Eclipse Java IDE the library is already included. It simply can be added to a project’s build path, which will be sufficient throughout this tutorial. To get your own copy please refer to Download and Install, for maven integration look at Using JUnit and if you happen to need an OSGi bundle you make a find at the eclipse orbit downloads.

Usually it is a good idea to start with the Happy Path, which is the ‘normal’ path of execution and ideally the general business usecase. For the SUT NumberRangeCounter this might be a test to verify, that the counter returns consecutive numbers on subsequent invocations of a method, which still has to be defined.

An executable JUnit test is a public, non static method that gets annotated with @Test and takes no parameters. Summarizing all this information the next step could be the following method stub4:

public class NumberRangeCounterTest {
  
  @Test
  public void subsequentNumber() {    
  }
}

Still not much, but it is actually sufficient for JUnit to run the test the first time. JUnit test runs can be launched from command line or a particular UI, but for the scope of this tutorial I assume that you have an IDE integration available. Within Eclipse the result would look like this5:

greenbar

The green bar signals that the test run did not recognize any problems. Which is not a big surprise, as we have not tested anything yet. But remember we have already done some useful considerations that can help us to populate our first test easily:

  1. We intent to write a unit NumberRangeCounter that is responsible for delivering a consecutive sequence of integer values. To test it we could create a local variable that takes a new instance of such a counter.
  2. @Test
      public void subsequentNumber() {    
        NumberRangeCounter counter = new NumberRangeCounter();
      }
  3. As the first test should assert that numbers provided by the NumberRangeCounter are consecutive integer values, meaning 5, 6, 7 or the like, the SUT could use a method providing those values. Furthermore this method could be called twice to provide a minimum set of subsequent values.
  4. @Test
      public void subsequentNumber() {    
        NumberRangeCounter counter = new NumberRangeCounter();
    
        int first = counter.next();
        int second = counter.next();
      }

Looks reasonable so far, but how can we assure that a test run is denoted as failure, if the value of second is not a valid successor of first? JUnit offers for this purpose the class org.junit.Assert, which provides a set of static methods to help developers to write so called self-checking tests.

The methods prefixed with assert are meant to check a certain condition, throwing an AssertionError on a negative result. Such errors are picked up by the JUnit runtime and mark the test as failed in the resulting report.

Update 2014/08/13: Using org.junit.Assert is just one possibility. JUnit also includes a matcher library Hamcrest, which many people consider a better solution regarding clean code. Personally I like the syntax of a third party library called AssertJ best.

I think that Assert might be more intuitive for beginners, so I choose it for this ‘hello world’ post. Due to the comments on that decision I realized that I have to mention these other possibilities at least at this point. I will elaborate on the usage of Hamcrest and AssertJ in a follow up post.

To assert that two values or objects are equals it is plausible to use Assert#assertEquals. As it is very common to use static imports for assertion method calls, the subsequentNumber test could be completed like this:

@Test
  public void subsequentNumber() {    
    NumberRangeCounter counter = new NumberRangeCounter();

    int first = counter.next();
    int second = counter.next();

    assertEquals( first + 1, second );
  }

As you can see, the test specifies an important behaviour of the SUT, which does not even exist yet. And by the way, this also means that the test class does not compile anymore!  So the next step could be to create a skeleton of our unit to solve this problem.

Although this tutorial is about JUnit and not TDD, I have chosen to insinuate the latter approach to emphasize the specification character clean JUnit test cases can have. Such an approach shifts the work focus from the unit’s inwards more to its usage and low level requirements.

If you want to learn more about TDD, in particular the Red/Green/Refactor mantra used to implement a single unit the books Test-Driven Development By Example by Kent Beck or Test Driven by Lasse Koskela might be a good evening read.

The following snippet shows a how the NumberRangeCounter stub would look like:

public class NumberRangeCounter {

  public int next() {
    return 0;
  }
}

Running the test again, now leads to a red bar due to the insufficient implementation of NumberRangeCounter#next(). This allows to ensure that the specification has not been met accidently by a useless verification or the like:

redbar

Additionally to the red bar the execution report shows how many tests have been run in total, how many of those terminated with errors, and how many have failed due to wrong assertions. A stacktrace for each error/failure helps to find the exact location in the test class.

An AssertionError provides an explanatory message, which is shown in the first line of the failure trace. Whereas a test in error may indicate an arbitrary programming mistake, causing an Exception to be thrown beyond the test’s assertion statements.

Note that JUnit follows the all or nothing principle. This means if a test run involves more then one test, which is usually the case, the failure of a single test marks the whole execution as failed by the red bar.

As the actual implementation of a particular unit is of minor interest for the topic of this article, I leave it up to you to come up with an innovative solution to make our first test pass again!

Conclusion

The previous sections explained the very basics of a JUnit test – how it is written, executed and evaluated. While doing so I placed value on the fact that such tests should be developed with the highest possible coding standards one could think of. The given example was hopefully well-balanced enough to provide a comprehensible introduction without being trivial. Suggestions for improvements are of course highly appreciated.

The next JUnit in a Nutshell post will continue the example and cover the general concept of a test case and its four-phase test structure, so stay tuned.
 

  1. Do not get me wrong – I like the book very much, but the general purpose approach is probably not the best way for getting started: xUnit Test Patterns, Gerard Meszaros, 2007
  2. Other studies are listed at http://biblio.gdinwiddie.com/biblio/StudiesOfTestDrivenDevelopment and a comparative analysis of empirical studies can be found at https://tuhat.halvi.helsinki.fi/portal/files/29553974/2014_01_swqd_author_version.pdf
  3. See also: Keeping Tests Clean, Clean Code, Chapter 9, Robert C. Martin 2009
  4. There are diverging opinions on how to name a test method. I have written down some considerations about this topic in Getting JUnit Test Names Right
  5. For more information on how to work with JUnit in Eclipse you might like to read my post Working Efficiently with JUnit in Eclipse
Reference: JUnit in a Nutshell: Hello World from our JCG partner Frank Appel at the Code Affine blog.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Back to top button