Categories: Java, Unit Tests

JUnit and Mockito handbook

junit-mockito-handbookOne of the most important concepts to build a software with quality is the automated tests. Going deep into the automated tests, one of its most explored branches is the unit tests. This article will show an overview about unit tests and then a practical “JUnit and Mockito handbook”, presenting their most useful features and some usage examples.

What is a unit test?

A unit test is a piece of code written by a developer that executes a specific functionality in the code to be tested. The percentage of code which is tested by unit tests is typically called test coverage.

A unit test targets a small unit of code, generally a method from a class.

Unit tests ensure that code works as intended. They are also very helpful to ensure that the code still works as intended in case you need to modify code for fixing a bug or extending functionality. Having a high test coverage of your code allows you to continue developing features without having to perform lots of manual tests.

What are the values of unit tests?

One of the most valuable benefits of unit tests is that they give you confidence that your code works as you expect it to work. Unit tests give you the confidence to do long-term development because with unit tests in place, you know that your foundation code is dependable. Unit tests give you the confidence to refactor your code to make it cleaner and more efficient.

 

Unit tests also save you time because unit tests help prevent regressions from being introduced and released. Once a bug is found, you can write a unit test for it, you can fix the bug, and the bug can never make it to production again because the unit tests will catch it in the future.

Another advantage is that unit tests provide excellent implicit documentation because they show exactly how the code is designed to be used.

Unit tests best practices

Which specific behaviour are you testing? It’s counterproductive to Assert() anything that’s also asserted by another test: it just increases the frequency of pointless failures without improving unit test coverage one bit. This also applies to unnecessary Verify() calls – if it isn’t the core behaviour under test, then stop making observations about it!

 

Test all classes independently, not chained with other classes. Otherwise, you have lots of overlap between tests, so changes to one unit can cascade outwards and cause failures everywhere.

You’ve definitely taken a wrong turn if you have to run your tests in a specific order, or if they only work when your database or network connection is active.

Avoid having common setup code that runs at the beginning of lots of unrelated tests. Otherwise, it’s unclear what assumptions each test relies on, and indicates that you’re not testing just a single unit.

 

Testing frameworks for Java

There are several testing frameworks available for Java. The most popular ones are JUnit and TestNG.

The “Arrange – Act – Assert” pattern

“Arrange-Act-Assert” is a pattern for arranging and formatting code in unit test methods:

Each method should group these functional sections, separated by blank lines:

The main benefit of this pattern is the clearly separation of what is being tested from the setup and verification steps. It improves the test legibility and maintainability.

The JUnit framework

JUnit in version 4.x is a test framework which uses annotations to identify methods that specify a test.

Sitehttp://junit.org/

GitHubhttps://github.com/junit-team/junit

Naming convention

There are several potential naming conventions for JUnit tests. In widespread use is to use the name of the class under test and to add the “Test” suffix to the test class.

You should prefer the “Test” suffix over “Tests” as the Maven build system (via its surfire plug-in) automatically includes such classes in its test scope.

For the test method names it is frequently recommend to use the word “should” in the test method name, as for example “ordersShouldBeCreated” or “menuShouldGetActive” as this gives a good hint what should happen if the test method is executed.

As a general rule, a test name should explain what the test does so that it can be avoided to read the actual implementation.

Annotations

JUnit 4.x uses annotations to mark methods and to configure the test run. The following table gives an overview of the most important available annotations.

Annotation

Description

@Test
public void method()

The @Test annotation identifies a method as a test method.

@Test (expected = Exception.class)

Fails if the method does not throw the named exception.

@Test(timeout=100)

Fails if the method takes longer than 100 milliseconds.

@Before
public void method()

This method is executed before each test. It is used to prepare the test environment (e.g., read input data, initialize the class).

@After
public void method()

This method is executed after each test. It is used to cleanup the test environment (e.g., delete temporary data, restore defaults). It can also save memory by cleaning up expensive memory structures.

@BeforeClass
public static void method()

This method is executed once, before the start of all tests. It is used to perform time intensive activities, for example, to connect to a database. Methods marked with this annotation need to be defined as static to work with JUnit.

@AfterClass
public static void method()

This method is executed once, after all tests have been finished. It is used to perform clean-up activities, for example, to disconnect from a database. Methods annotated with this annotation need to be defined as static to work with JUnit.

@Ignore

Ignores the test method. This is useful when the underlying code has been changed and the test case has not yet been adapted. Or if the execution time of this test is too long to be included.

Asserts

JUnit provides static methods in the Assert class to test for certain conditions. These assertion methods typically start with assert and allow you to specify the error message, the expected and the actual result. An assertion method compares the actual value returned by a test to the expected value, and throws an AssertionException if the comparison test fails.

Statement

Description

fail(String)

Let the method fail. Might be used to check that a certain part of the code is not reached or to have a failing test before the test code is implemented. The String parameter is optional.

assertTrue([message], boolean condition)

Checks that the boolean condition is true.

assertFalse([message], boolean condition)

Checks that the boolean condition is false.

assertEquals([String message], expected, actual)

Tests that two values are the same. For complex objects, its reference is compared.

assertEquals([String message], expected, actual, tolerance)

Test that float or double values match. The tolerance is the number of decimals which must be the same.

assertNull([message], object)

Checks that the object is null.

assertNotNull([message], object)

Checks that the object is not null.

assertSame([String], expected, actual)

Checks that both variables refer to the same object.

assertNotSame([String], expected, actual)

Checks that both variables refer to different objects.

The Mockito framework

Mockito is a popular mock framework which can be used in conjunction with JUnit. Mockito allows you to create and configure mock objects.

Sitehttp://site.mockito.org/

GitHubhttps://github.com/mockito/

Documentation:

http://site.mockito.org/mockito/docs/current/org/mockito/Mockito.html

http://site.mockito.org/mockito/docs/current/org/mockito/Matchers.html

http://site.mockito.org/mockito/docs/current/org/mockito/AdditionalMatchers.html

Main features

Mockito’s main features are:

Limitations

Mockito has certain limitations. It cannot test the following constructs:

i.e.: the methods of String class cannot be stubbed (because String is a final class)

i.e.: int, boolean, double, float

Annotations

Annotation

Description

@Mock

Creates a mock of a given type. We can use @Mock to create and inject mocked instances without having to call Mockito.mock manually.

@Spy

Creates a spy of a given object. We can use @Spy to create and inject spied instances without having to call Mockito.spy manually.

@Captor

Creates an argument captor of a given type

@InjectMocks

Creates an object of a given type and injects
mocks and spies existing in a test.

Important mocking concepts

Mocks

Pre-programmed objects with expectations which form a specification of the calls they are expected to receive. Methods in a mock object returns the default values of return type.

Spies

Pre-programmed objects with expectations which form a specification of the calls they are expected to receive. Methods in a spy object returns real responses from the methods unless the method is stubbed.

Stubs

Stubs provide canned answers to calls made during the test, usually not responding at all to anything outside what’s programmed in for the test. In Mockito the stubs are made in Mock objects.

Using Mockito in the JUnit Tests

Mocking an object

or

Spying an object

or

Stubbing methods on mocks (and spies) without parameters

stubbing return values

stubbing to throw an exception

Stubbing methods on mocks (and spies) with non-specific parameter values

To stub methods with non-specific parameters we can use Argument Matchers.

stubbing using built-in anyInt() and anyString() argument matcher

Stubbing methods on mocks (and spies) with specific parameter values

stubbing using built-in eq argument matcher

Argument matchers

The following table shows only the most common argument matchers. The complete list of argument matchers can be found on the following link:

http://site.mockito.org/mockito/docs/current/org/mockito/Matchers.html

Method

Description

any()

Matches anything, including nulls

any(java.lang.Class<T> clazz)

Matches any object, including nulls

anyBoolean()

Any boolean or non-null Boolean

anyDouble()

Any double or non-null Double

anyFloat()

Any float or non-null Float.

anyInt()

Any int or non-null Integer

anyLong()

Any long or non-null Long

anyString()

Any non-null String

argThat(org.hamcrest.Matcher<T> matcher)

Allows creating custom argument matchers

contains(java.lang.String substring)

String argument that contains the given substring

startsWith(java.lang.String prefix)

String argument that starts with the given prefix

endsWith(java.lang.String suffix)

String argument that ends with the given suffix

eq(boolean value)

boolean argument that is equal to the given value

eq(double value)

double argument that is equal to the given value

eq(int value)

int argument that is equal to the given value

eq(T value)

Object argument that is equal to the given value

isA(java.lang.Class<T> clazz)

Object argument that implements the given class

isNotNull()

Not null argument

isNull()

null argument

matches(java.lang.String regex)

String argument that matches the given regular expression

same(T value)

Object argument that is the same as the given value

Additional argument matchers

Additional matchers provides rarely used matchers. Use additional matchers very judiciously because they may impact readability of a test. It is recommended to use matchers from Matcher sand keep stubbing and verification simple.

The complete list of additional arguments matchers can be found on the following link:

http://site.mockito.org/mockito/docs/current/org/mockito/AdditionalMatchers.html

A few examples:

Verifying exact number of mock’s invocations / at least x / never

References

Article info