Sie sind auf Seite 1von 35

GO AWAY, BUGS!

KEEPING YOUR CODE SAFE WITH JUNIT,


TESTNG AND MOCKITO

O h no!

All rights reserved. 2013 ZeroTurnaround O 1


TABLE OF
CONTENTS
INTRODUCTION
KEEPING YOUR CODE SAFE WITH UNIT TESTING - 1

PART I
JUNIT AND TESTNG FOR ADVANCED GURU-TYPES - 2-13

PART II
FIGURING OUT WHAT TO TEST... - 14-16

PART III
SETTING UP MOCK ALTERNATE REALITIES - 17-20

PART IV
MOCKITO FOR ADVANCED USERS (WOOHOO!) - 21-28

TOO LONG, DIDN'T READ (TL;DR)


SUMMARY, CONCLUSION, FAREWELL AND A COMIC - 29-30

All rights reserved. 2013 ZeroTurnaround O 2


INTRODUCTION
KEEPING YOUR CODE SAFE
WITH UNIT TESTING
Unit tests let developers internally control the functionality and
compatibility of their applications when they made changes to
features, code or the environment.

All rights reserved. 2013 ZeroTurnaround O 3


Believe it or not, unit testing is actually a controversial topic among Java developers. Some think that writing unit tests
is a waste of time, while others consider them an essential part of the software development process, and the way to
ensure that your new app doesnt, well, suck because it wasnt checked properly. And yet some developers are bored by
the topic of unit tests.

THINK OF THIS ANALOGY:


Each time you enter your car and start it up, you take a look at the If you really, really know what you are doing, then you might disregard
instrument panel/dashboard, almost automatically. Even older cars are some of them. But this is not the normal case. And like the car analogy,
equipped with warning lights, some less serious (like that you need to fill your car without any warning might suddenly stop working (for reasons not
gas), some more serious (like the battery status) and some highly critical detected by the status lights), just like how code that passes all unit tests is
(like the engine-is-gonna-explode warning light) not necessarily 100% correct.

So if you see something wrong, like the "check engine" light is flashing an Before we get into the blood and guts of the report, lets review a
angry red warning, it probably wouldn't be wise to start driving away. In a very brief list of points to remember:
similar manner unit tests act as warning signals that something does not
Unit tests are code themselves (so they might also have bugs, ha!)
work as expected. It wouldn't be wise to deploy code into production when
all your unit tests are failing. Unit tests perform a small task and then verify that the result is the
expected one

But unit tests are just that, early warnings and internal checks that your Unit tests that are failing are a warning signal that something is
code does what is expected. wrong with the expectations of the system
Unit tests that pass do not guarantee 100% correctness of the code.
Unit tests should be updated if the requirements change

All rights reserved. 2013 ZeroTurnaround O 1


PART I
JUNIT AND TESTNG FOR
ADVANCED GURU-TYPES
JUnit is one of the most popular testing frameworks available, and TestNG brings some
more advanced enterprise features to your ongoing efforts to keep your code clean,
testable and verifiable at all stages of application development and deployment.

All rights reserved. 2013 ZeroTurnaround O 2


If youve heard anything about unit tests in Java before, then youll know that the de facto testing
framework is JUnit, so most of our examples will use it and the major Java IDEs (i.e. Eclipse,
IntelliJ IDEA, NetBeans) have explicit support for it.

JUnit is a port to Java from the original SUnit from Smalltalk created by Kent Beck. Since
then similar libraries exist for other language as well such as nUnit, phpUnit, Cunit. Here is a
comprehensive list of other testing frameworks

TestNG (test next generation) is another framework for Java, which can be seen as a more
advanced JUnit. It is also possible to use other test frameworks for languages that run on the
JVM to test Java code. Spock which is the test framework of Groovy can be used to test both Java
and Groovy code.

Note: Unfortunately, we have limited space in this report, so well ask you to view
certain parts of this content on the ZeroTurnaround blog. The following parts appear
in Why Your Next Cloud App Will Probably Suck Without.Unit Testing:

Get started by setting up a Hello World! unit test, will all the code
you need to make it happen
Seeing your unit tests from the end-user perspective, driven by the
features required.
Unit testing as a warning signal for later (i.e. what happens we a new
dev joins your team in 2 years and starts playing with legacy code?)

However, lets continue with some more advanced stuff for those of you who already checked
out the blog. Please note that, unfortunately, some code snippets are too long to fit in one
column, and therefore carry over to the next. We are planning a fix for this in the future,
apologize for this inconvenience.

All rights reserved. 2013 ZeroTurnaround O 3


JUnit setup & tear-down
After you have written your first JUnit class you might think that unit testing @Test
is a tedious process that deals with large amounts of low level code. The public void test3() {
MyUriValidator myValidator = new MyUriValidator();
reality is however the JUnit (and more extensively TestNG) have several
myValidator.allowFileUrls(true);
features that make your life easier. myValidator.allowInternationlizedDomains(false);
myValidator.allowReservedDomains(false);
myValidator.allowCustomPorts(true);
Assume that you have already implemented a class that checks the validity
for URLs called MyUriValidator. The class needs several statements to set assertFalse("Domain is invalid",myValidator.
up correctly. So your first attempt for a unit test might be: isValidUrl("http://localhost:8080/"));
}
public class MyUriValidatorTest {

@Test There is clearly a lot of code duplication here. JUnit has a @Before
public void test1() { annotation for code that runs automatically before each test method. So
MyUriValidator myValidator = new MyUriValidator();
your test can be simplified to:
myValidator.allowFileUrls(true);
myValidator.allowInternationlizedDomains(false);
myValidator.allowReservedDomains(false); public class MyUriValidatorTest {
myValidator.allowCustomPorts(true);
private MyUriValidator myValidator = null;
assertTrue("Domain is valid",myValidator.
isValidUrl("http://www.google.com")); @Before
} public void beforeEachTest() { //Name of method does not
actually matter
@Test myValidator = new MyUriValidator();
public void test2() { myValidator.allowFileUrls(true);
MyUriValidator myValidator = new MyUriValidator(); myValidator.allowInternationlizedDomains(false);
myValidator.allowFileUrls(true); myValidator.allowReservedDomains(false);
myValidator.allowInternationlizedDomains(false); myValidator.allowCustomPorts(true);
myValidator.allowReservedDomains(false); }
myValidator.allowCustomPorts(true);
@Test
assertTrue("Domain is valid",myValidator. public void test1() {
isValidUrl("file://home/users")); assertTrue("Domain is valid",
} myValidator.isValidUrl("http://www.
google.com"));

All rights reserved. 2013 ZeroTurnaround O 4


} @Before
public void dbSetup()
@Test {
public void test2() { // Will actually run twice (for test1 and test2)
assertTrue("Domain is valid", System.out.println("Preparing db Connection");
myValidator.isValidUrl("file://home/ myDbConnection = new MyDbConnection();
users")); myDbConnection.connect();
} }

@Test @After
public void test3() { public void dbTearDown()
assertFalse("Domain is invalid", {
myValidator.isValidUrl("http:// // Will actually run twice (for test1 and test2)
localhost:8080/")); System.out.println("Cleaning up");
} myDbConnection.releaseConnection();
}
}
@Test
public void test1() {
There is also the respective @After annotation (runs after each test), as System.out.println("Test 1 runs");
well as @BeforeClass and @AfterClass annotations for code that runs myDbConnection.doSomethingElseWithDb();
ONCE before/after all tests. //Assert statements should be here for this test to be complete
}

You use the @After annotation to clear up resources requested in the @Test
@Before. Here is an example for an integration test where a database public void test2() {
System.out.println("Test 2 runs");
connection is created in the beginning and released in the end for EACH myDbConnection.doSomethingElseWithDb();
test. //Assert statements should be here for this test to be complete
}
import org.junit.After; }
import org.junit.Before;
import org.junit.Test; If you run this test it will print the following (broken due to space issues):
public class SimpleDatabaseTest { Preparing db Connection Test 2 runs
Cleaning up Preparing db Connection
private MyDbConnection myDbConnection= null;
Test 1 runs Cleaning up

All rights reserved. 2013 ZeroTurnaround O 5


The @BeforeClass and @AfterClass can be used for expensive objects public void test1() {
System.out.println("Test 1 runs");
that need to be created only once. Be careful however with state changes.
earthQuakeSimulator.simulateEarthQuakeInAsia();
Your unit tests should be self-contained and with no side effects. This lets earthQuakeSimulator.resetEarthToInitialState();
them remain completely independent so that you can run them in any // Assert statements should be here for this test to
be complete
order (or even in parallel).
}

Here is an example where an expensive object (an earthquake @Test


public void test2() {
simulation module) is created only once during the tests:
System.out.println("Test 2 runs");
earthQuakeSimulator.simulateEarthQuakeInEurope();
import org.junit.AfterClass; earthQuakeSimulator.resetEarthToInitialState();
import org.junit.BeforeClass; // Assert statements should be here for this test to
import org.junit.Test; be complete
}
public class EarthQuakeTest {
private static EarthQuakeSimulator earthQuakeSimulator = }
null;

@BeforeClass Notice that the annotated methods for @BeforeClass and @AfterClass
public static void prepareSimulation() { are declared static (this is a limitation of JUnit, but TestNG is more
// Will run only once regardless the number of tests
System.out.println("Preparing earthquake
flexible). If you run this unit test you will get:
simulation");
earthQuakeSimulator = new EarthQuakeSimulator(); Preparing earthquake simulation
earthQuakeSimulator.startup(); Test 1 runs
}
Test 2 runs
@AfterClass Cleaning up
public static void endSimulation() {
// Will run only once regardless the number of tests
These annotations are also very useful when you use a specific helper for
System.out.println("Cleaning up");
earthQuakeSimulator.shutdown(); a test (e.g an integration framework or an in-memory database) that you
} want to use for all your tests.

@Test

All rights reserved. 2013 ZeroTurnaround O 6


JUnit parameterized tests
So with the help of the @Before annotations we have much
{"http://localhost:8080/",
false } });
less code duplication. Continuing with the example of the
MyUrlValidator we still see that we have to create a new return uriToBeTested;
method each time a new URL needs to be tested. JUnit supports }
parameterised tests where you write a general test method once,
@Before
then a separate method provides the data. public void beforeEachTest() {
myValidator = new MyUriValidator();
myValidator.allowFileUrls(true);
Here is the approach for that:
myValidator.allowInternationlizedDomains(fa
lse);
@RunWith(Parameterized.class)
myValidator.allowReservedDomains(false);
public class MyUriValidatorTest {
myValidator.allowCustomPorts(true);
}
private MyUriValidator myValidator = null;
private String uriTestedNow =null;
@Test
private boolean expectedResult = false;
public void testCurrentUri() {
assertEquals("Testing for "+uriTestedNow,
public MyUriValidatorTest(String
expectedResult,myValidator.isValidUrl(uriTestedNow));
uriTestedNow,boolean expectedResult)
}
{
this.uriTestedNow = uriTestedNow;
}
this.expectedResult = expectedResult;
}
As you can see, adding a new URL is a single line change in the
@Parameters the method annotated as Parameters.
public static Collection data() {
/* First element is the URI, second is the
expected result */
List uriToBeTested = Arrays.asList(new Object[]
[] {
{ "http://www.google.com",
true },

{ "file://home/users", true },
{ "http://staging:8080/
sample", true },

All rights reserved. 2013 ZeroTurnaround O 7


Exception testing with JUnit Extending JUnit with rules
Occasionally, you might want to verify in your unit test that a method JUnit @Rule annotation allows you to smoothly change or extend the
throws some specific exception. Prior to JUnit 4, you might have achieved behaviour of your test methods. There are 8 rules provided by the JUnit
this by writing a try-catch block inside a test method so that test would library: ErrorCollector, ExpectedException, ExternalResource,
pass if the catch block is reached. JUnit 4 provides more elegant way to TemporaryFolder, TestName, TestWatchman, Timeout and Verifier.
test such exceptional cases. We are going to cover only few of these in the current section. But whats
cool is that you can extend this list by writing your own rules!
Let's assume that the BasketWeightCalculator class from the
Let's get back to our addItem() method that throws
introductory blog post has been changed so that addItem() method will
IllegalArgumentException in certain cases. What if we need to check
throw IllegalArgumentException if it gets a negative argument passed
that this exception gets thrown and it has a specific message? With JUnit's
to it. How to test it? With JUnit 4 it is nice and clean:
ExpectedException rule we could write the test as follows:
@Test(expected= IllegalArgumentException.class)
@Rule
public void shouldNotAddNegativeWeights() {
public ExpectedException thrown = ExpectedException.none();
weightCalculator.addItem(-5);
}
@Test
public void shouldNotAddNegativeWeights() {
When you need to verify that the thrown exception has a specific thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("Cannot add negative weight");
message bundled with it, then you could use JUnit's ExpectedException
weightCalculator.addItem(-5);
rule. The next sections goes into greater detail on @Rule annotation. }

Another useful and simple-to-use rule is a Timeout rule. It sets the


timeout in milliseconds for each test method. When some test method
takes more time to execute, then this test fails. Let's verify that addItem()
method executes in 100 milliseconds:

@Rule
public Timeout timeout = new Timeout(100);

@Test
public void shouldAddItemsQuickly() {
weightCalculator.addItem(-5);
}

All rights reserved. 2013 ZeroTurnaround O 8


Grouping your unit tests with JUnit categories
The @Category annotation provides a way to divide test methods into @SuiteClasses( { FirstClassTests.class, SecondClassTests.class
groups. For example, to gather all test with similar properties (e.g. slow })
public class MyGroupATestSuite { }
tests) into one group. One test method can belong to many groups as the
following example shows for SecondClassTests.testSomething() test
In order to get it to actually work, we should define each category type
method.
(MyGroupA, MyGroupB, MyGroupC) as a Java interface. You can create
public class FirstClassTests { sub-types and parent-types by extending interfaces.

@Category(MyGroupA.class)
@Test
public void testSomething() { Multiple test arguments with JUnit theories
new FirstClass().testSomething();
} When you annotate the test method with @Theory keyword, then JUnit will
invoke this method with all possible combinations of variables declared as
@Category(MyGroupB.class)
@DataPoint (or @DataPoints, if you have packed the variables into an
@Test
public void testSomethingElse() { array).
new FirstClass().testSomethingElse();
}
For example, when we want to test some method which takes two integers
}
as parameters and we would like to run tests with such set of parameters: {
public class SecondClassTests { (0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)} then @Theory can help us to keep the
code compact.
@Category({MyGroupA.class, MyGroupC.class})
@Test
public void testSomething() { @RunWith(Theories.class)
new SecondClass().testSomething(); public class CombinationTest {
}
} @DataPoints public static int[] INTS = new int []{0, 1, 2, 3};

@Theory
Next, when we want to run all test methods belonging to group
public void testCalculation(int x, int y) {
MyGroupA, we need to create a test suite for that. Assume.assumeTrue(x < y);
new Combination().calculate(x, y);
@RunWith(Categories.class)
}
@IncludeCategory(MyGroupA.class)
}

All rights reserved. 2013 ZeroTurnaround O 9


Utilizing TestNG FEATURE JUNIT TESTNG
in addition to JUnit Purpose General unit testing
Focus on Integration testing for
Enterprise projects
TestNG is another testing framework IDE support yes Yes
for Java. It is inspired from JUnit and Maven support yes Yes
supports a lot more features aimed
setup/teardown for test @Before / @After @BeforeMethod / @AfterMethod
at development of Enterprise Java
applications. Some of its features are setup/teardown for class @Before / @After @BeforeClass / @AfterClass
so successful that have been copied/ setup/teardown for suite no @BeforeSuite / @AfterSuite
ported to JUnit as well. Or some JUnit
setup/teardown for test groups no @BeforeGroups/ @AfterGroups
features seem to draw inspiration for
TestNG, if you prefer! setup/teardown for test in annotations In annotations and/or XML file
Parameterised tests Yes, but in a limited way Yes
Here is an overview of features
Test groups Yes with Categories (new feature) Yes
supported by TestNG and how they
compare to JUnit. Test for Exceptions Yes Yes

Timeouts in tests Yes Yes


Can be defined in detail with
Test order Non-Deterministic or alphabetical dependencies
Dynamic test input No Yes with DataProviders

Can run tests of the other library No Yes, TestNG can run JUnit tests

Assumptions before running a test Yes No

Dependency injection for tests No Yes, with Google Guice


Ignore/disable test Yes Yes

Parallel testing No Yes


Test listeners No Yes

Test reporters No Yes

All rights reserved. 2013 ZeroTurnaround O 10


Some of the most interesting features of TestNG Lets re-write the improved MyURLValidator test with TestNG:
(not offered by JUnit) are:
import org.testng.annotations.BeforeMethod;
1. Powerful parameterized tests with data providers that choose input import org.testng.annotations.DataProvider;
data during run-time import org.testng.annotations.Test;
2. Parallel testing of test cases for increased performance
public class MyUriValidatorTest {
3. Dependencies among test cases and complete control over the
order of the tests run private MyUriValidator myValidator = null;

The third capability is very powerful but also needs great attention if @BeforeMethod
public void beforeEachTest() {
you choose to use it. Normally, all your test cases should be completely myValidator = new MyUriValidator();
independent and they should be able to execute in any order. No test myValidator.allowFileUrls(true);
should have side effects, and no test should depend on the outcome of myValidator.allowInternationlizedDomains(false);
myValidator.allowReservedDomains(false);
another one. myValidator.allowCustomPorts(true);
}
But lets look at the first two features we mentioned above:
Parameterized and Parallel testing @DataProvider
private static final Object[][] createSamples() {
return new Object[][] { { "http://www.google.com",
SUPER-POWERED PARAMETERIZED TESTS WITH TESTNG true },
While JUnit has basic support for parameterized tests, the approach it { "file://home/users", true },
{ "http://localhost:8080/", false } };
follows is not very flexible. As you saw in the MyUrlValidator example, }
parameters exist as private fields in your test class, and also a special
constructor is needed. @Test(dataProvider = "createSamples")
public void testURL(String uriTested, boolean
expectedResult) {
Wouldnt it be great to add parameters as arguments into the test method
assertEquals(myValidator.isValidUrl(uriTested),
themselves without polluting the test class with extra fields? Of course it expectedResult,
would! This is exactly what TestNG does. "Test for " + uriTested);
}
TestNG introduces the concept of a Dataprovider, which is a way to create
test data and bind it to test methods. Binding happens via the name of the }

data provider, and the test data and test code are completely decoupled
and you are free to connect them as you want. This offers much more
flexibility than JUnit.

All rights reserved. 2013 ZeroTurnaround O 11


As you can see, the code is much more compact. Even better is the fact TestNG on the other hand directly reports both the argument and the
that the data provider and the test method are decoupled, meaning that result so that you can see at a glance where the problem lies. For test cases
you can have multiple data providers and many test methods with any with a large number of parameters (e.g. hundreds) this can be a huge time
combination of binding between them. saver.

With a big number of parameters, error reporting is somewhat lacking in TestNG also supports having the DataProvider and the test method in
JUnit. JUnit will number each test argument in sequence, giving no direct completely different classes, allowing for even better code reuse.
indication what was the argument. If we create a failed test where only one
argument did not pass you get the following: Here is the DataProvider class on its own:

public class SampleURLStrings {


@DataProvider
private static final Object[][] createSamples() {
return new Object[][] { { "http://www.google.com",
true },
JUnit results { "file://home/users", true },
{ "http://localhost:8080/", true } };
}
}

And here is the unit test that references this dataProvider

@Test(dataProvider = "createSamples", dataProviderClass =


SampleURLStrings.class)
TestNG results
public void testURL(String uriTested, boolean
expectedResult) {
assertEquals(myValidator.isValidUrl(uriTested),
expectedResult,
"Test for " + uriTested);
}

In a big enterprise project, it might be very helpful to centralize all test data
in a single place for easier management of new requirements that affect
those test cases that have yet to be verified.

All rights reserved. 2013 ZeroTurnaround O 12


PARALLEL TESTING WITH TESTNG
Assuming that your tests are written correctly (i.e. they are independent Whew! This section was a bit intense. Now that youve seen some advanced
of each other), you have the option to run them in parallel. This speeds features of JUnit and TestNG, plus a comparison between the two tools, its
up the build in most cases and its very handy when your TestNG tests are probably best now to discuss what to test and how. After all, understanding
executed in the build server (e.g. Jenkins) as part of your build process. parameterized tests, method rules, categories, theories, and how to do
parallel testing without external support from Maven, figuring out where to
TestNG has built-in support for running tests in parallel. It is possible to start with your own tests is the next logical step...
do this in JUnit as well, but you need external support, like using Maven.
In TestNG you just add two more attributes in the testng.xml file of your
suite. Here is an example:

<?xml version="1.0" encoding="UTF-8"?>


<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite thread-count="10" name="Suite" parallel="methods"
verbose="1">
<test name="report-sample">
<classes>
<class name="com.zeroturnaround.quakes.QuakeSimulator"/>
<class name="com.zeroturnaround.quakes.QuakeSimulator2"/>
</classes>
</test>
</suite>

Notice the added parallel and thread-count XML properties. These


instruct TestNG to use multiple threads for executing the defined tests. The
count value defines how many threads to use (i.e. size of thread pool). The
parallel value is usually one of the following:

methods - This is the most useful option for using parallelism at


a fine-grained level
classes - Coarse-grained parallelism

All rights reserved. 2013 ZeroTurnaround O 13


PART II
FIGURING OUT WHAT TO TEST...
So now that you know what are unit tests, why are they needed and how they can
help you as a developer, perhaps you are thinking you are going to test the gigantic
enterprise application of your company that contains thousands of lines of code.
Where do you start?

All rights reserved. 2013 ZeroTurnaround O 14


Dont test everything...
Before writing a single unit test, its necessary to determine exactly what to test. A big enterprise application can hold a billion
lines of code, so it is realistic to write tests for everything? Not exactly. So, its important to make sure your tests are focused on
what actually matters to you, your app and your users.

Lets see what you should NOT test and get it out of the way first:

Other framework libraries (you should assume they work correctly)


The database (you should assume it works correctly when it is available)
Other external resources (again you assume they work correctly when available)
Really trivial code (like getters and setters, for example)
Code that has non-deterministic results (i.e. thread order or random numbers)

What you SHOULD test


One of the golden rules of unit testing is that
your tests should cover code with business
logic. Here is the typical flow in a back-end
processing system. Your web application could
look like this:

All rights reserved. 2013 ZeroTurnaround O 15


In this case, the highlighted part in gold is where you should focus your testing efforts. This is the part of the code where usually
most bugs manifest. It is also the part that changes a lot as user requirements change since it is specific to your application.

So what happens if you get across a legacy application with no unit tests? What if the business logic part ends up being
thousands of lines of code? Where do you start?

In this case you should prioritize things a bit and just write tests for the following:

Core code that is accessed by a lot of other modules


Code that seems to gather a lot of bugs
Code that changes by multiple different developers (often to accommodate new requirements)

How much of the code in these areas should we test, you might ask. Well, now that we know which areas to focus on, we can now
start to analyze just how much testing we need to feel confident about our code.

Note: Due to space limitations, well kindly ask you to visit the ZeroTurnaround blog if youd like to see more content
on Code Coverage, which is a metric that tells you how much of your code is touched by your unit testing efforts.
We covered this in Dont Test Blindly: The Right Methods for Unit Testing Your Java Apps.

All rights reserved. 2013 ZeroTurnaround O 16


PART III
SETTING UP MOCK
ALTERNATE REALITIES
Unit Testing is great to use when you start writing a new application and everything is
clean and pristine. But what if you inherit a mess of code inside some huge enterprise
application, and everything you need to deal with is already there, and ideally working
correctly?

All rights reserved. 2013 ZeroTurnaround O 17


Just when you thought everything was going so well, we throw a monkey wrench into your new unit
testing world...because with complex legacy applications, you cannot simply start implementing your
own unit tests out of the blue.

For example, if you change something, how can you tell what will be affected? The side effects
of your changes should be clear from the beginning, and we do this by Mocking, which lets you
create alternative realities for your application to play through, without having any side effects or
consequences in reality (kinda like the Truman show :)

Note: We dont have all the space wed like to provide all the code examples for Mocking, so
please see the ZeroTurnaround blog post, How to mock up your Unit Test environment to
create alternate realities for details on:

How to test the side effects of what you change


How to manually mock up Java Objects, if you dare (something we
dont recommend!)
Getting started with Mockito (the most popular mocking
framework) and a note on testable code

For now, lets see why using a Mocking Framework is better than doing anything by hand, and some of
the tools available.

All rights reserved. 2013 ZeroTurnaround O 18


Dont Mock by Hand: Use a Mocking Framework
At RebelLabs we sometimes say that smart + lazy = efficient. So why create a bunch of human-error prone manual tests on-the-fly
when you could be so much lazier and use a mocking framework, such as Mockito, EasyMock, JMockit and others in this great, if a bit
dated, comparison.

Mocking attempts to solve in an easy way the creation of fake objects that help the unit testing process. Like our comparison to the
Truman Show, mock objects are designed to fool a Java object to think that it communicates with other real objects.

From the point of view of the tested class (i.e. the FinalInvoiceStep of the example provided in the blog post), everything runs
normally. It communicates with other objects and gets all the appropriate responses. Behind the scenes however, this is only theater, a
mummers show if you will, which has been carefully planned by you.

The mock objects within your library allow


you to setup a controlled environment with
strictly-defined deterministic behaviours by
all objects involved with the class in question.
Ive added a visual here as an overview of
mocking:

All rights reserved. 2013 ZeroTurnaround O 19


In your new theater, you should use a mocking framework to set the Sending an overdue bill notification to a client via email
stage, in which you carefully monitor all interactions of the tested class Sending a request to an external system
in order to verify its effectiveness. Then you can see if all your actors
Launching weapons into a neighboring enemy solar system
performing properly.
Flooding the reactor core
So when should you use mocking? Shutting down life support

We suggest using mocking when the class you want to unit test
Ok, that list is a bit morbid, but you get the point. You can also use
communicates with other classes that have side effects which should only
mocking in other cases as well. A common practice is to mock some
be called in the real production system. Some random examples, with
classes that are very slow and based on a lot of dependencies not needed
significant side effects in real life, are:
for the unit test. Mocking is also great when you want to emulate strange
errors such as a full hard disk, network failure, wrong serialized version
Charging a credit card or bank account
etc.
Printing medical records, invoices, personal documents, etc.

When NOT to use mocking


Always remember that you should mock the objects that your classes come in contact with, because you are interested in the class itself and nothing else.
If you actually want to see the interaction of the whole module then you need integration tests, something we will cover later.

Therefore you should not use mocking when you are interested in:

Data that comes from external resources or the DB (e.g. ResultSets)


Transactions
The interaction of your application with your application server or environment
Testing multiple modules together as a single component

For all these cases you need integration tests, because we are now looking beyond the classes themselves. If you have several objects that work correctly
isolated (because the unit tests pass), this does not mean that they will also work correctly when used together. This is where integration tests come in.

All rights reserved. 2013 ZeroTurnaround O 20


PART IV
MOCKITO FOR ADVANCED USERS
(WOOHOO!)
In this section we jump right into the heady brew that is Mockito. For the introductory
parts about getting set up with Mockito, you can visit How to mock up your Unit Test
environment to create alternate realities.

All rights reserved. 2013 ZeroTurnaround O 21


Getting your blender ready for your first mocks
Jumping right in, imagine you have a Spring web application--take
lr-demo-answers-java for example.This is also a Maven project,
so to unleash the power of Mockito onto this app we just need to
define a couple of test-scope dependencies:

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-core</artifactId>
<version>1.9.5</version>
<scope>test</scope>
</dependency>
I first started using Mockito in a big legacy code base with
lots of DaoFactories, ObjectManagers, Useless delegates
and other unncessery stuff. It allowed me to create
simple, fast unit tests that focused on one thing and one
thing only. The integration tests took hours (and nobody
paid attention to them in the team). But unit tests with
Mockito finished in seconds and after a while when most
of the team embraced them we would catch regression
errors before sending code to production.

Kostis Kapelonis
RebelLabs Content Producer

All rights reserved. 2013 ZeroTurnaround O 22


Now we have code to test and whole infrastructure set up, so we can proceed
straight to writing some tests and showing off Mockito features:

Lets look at EmailUniqueValidator, its just a normal ConstraintValidator which you can
think of as a util class that queries some service to base assumptions on the data. Theres
nothing special here; it includes a method isValid, which contains non-trivial logic to test.

We consider this try-catch nontrivial as it swallows exceptions and returns counterintuitively,


true if the service is unavailable. What is important to our example is that we call a
UserService instance, while pondering the validity of a given email. Mocking a service is what
Mockito excels at, so check out a sample test in EmailUniqueVisitorTest. Below we bring up
one of its test methods:

import static org.mockito.Mockito.*;


@Test
public void testNonUniqueEmailIsNotValid() {
String emailValue = "root@example.com";
UserService userService = mock(UserService.class);
User user = mock(User.class);
// we expect findByEmail be called
when(userService.findByEmail(emailValue)).thenReturn(user);
boolean valid = new EmailUniqueValidator().setUserService(userService).
isValid(emailValue, null);
assertFalse("email is valid despite there's a user with it", valid);
}

All rights reserved. 2013 ZeroTurnaround O 23


Almost all Mockito functionality is available through static methods, So there is Springockito, which allows you to annotate your tests and have
which allows us to use static imports and maintain code that is your mocks injected into their rightful places with almost no interactions.
surprisingly clean and readable.
"classpath:/context.xml")
public class SpringockitoAnnotationsMocksIntegrationTest extends
At the end of the test, a very thorough developer can also verify that AbstractJUnit4SpringContextTests {
mock methods have been called appropriately, even Mockitos official
@ReplaceWithMock
point of view is that this is almost always redundant in simple cases. The @Autowired
explanation is simple: if you dont properly stub some method that is private InnerBean innerBean;
important, your test will probably fail before the verification. So maybe ...

you shouldnt stub that method at all! }


This small example confirms that Mockito is a very powerful mocking
That is the basic example of mocking your services with Mockito. tool and despite the fact that we just touched the tip of this framework

Naturally, there are integrations with frameworks; when you use a iceberg, we showed how easy it can be to integrate your project, your

dependency injection framework, like Spring in the example above, you existing tests and Mockito.

want all your beans to be managed automatically.

When its pain to mock


Guess what? There are cases when you cannot mock something efficiently, usually in legacy or poorly-designed systems. So
your system might not be optimally designed and screams for refactoring, but sometimes theres no time to do this. And
prior to refactoring, it is good practice to cover your code with tests, unless you really like surprises and random bugs (fail!)

UserDetailWrapper has one method with logic: getAuthorities(). So imagine that you cannot mock User. Thats when
Mockitos spies come to the rescue. Instead of mocking an object and stubbing its interactions with the environment, a spy
wraps the object and delegates method calls to the real instance while providing all the monitoring features of a mock.

All rights reserved. 2013 ZeroTurnaround O 24


Taking a look at the UserDetailWrapperTest, you can see that spies are created from real User
instances, and a real User object is called when a wrapper tries to determine its authorities.

@Test
public void getAuthoritiesNoContactUser() {
// a real object is created and real object method will be called
User user = spy(new User());
UserDetailsWrapper wrapper = new UserDetailsWrapper(user);
Collection<? extends GrantedAuthority> authorities = wrapper.getAuthorities();
assertTrue("User has no contact, but has authorities!", authorities.isEmpty());
verify(user).getFacebookId();
verify(user).getEmail();
// verify id is not necessary if we have no facebook and no email
verify(user, never()).getId();
}

However, a spy allows us to verify that the Facebook and email getters of the underlying user object
were called and id getter wasnt. Isnt that great? Now you can build and verify your assumptions of
what the system is doing without modifying its functionality.

All rights reserved. 2013 ZeroTurnaround O 25


That was kind of easy: the real User instance didnt do anything important, but when we have a complex
system component coming from the outside, initialized and non-mockable, these Mockito spies are saviors!

@Test
public void normalUserHasAuthorities() {
// a real object is created and a real object method will be called
User realInstance = getComplexInitializedUser();
User user = spy(realInstance);
UserDetailsWrapper wrapper = new UserDetailsWrapper(user);
Collection<? extends GrantedAuthority> authorities = wrapper.getAuthorities();
verify(user).getFacebookId();
verify(user).getEmail();
verify(user).getId();
assertTrue("User has no id, but has authorities!", !authorities.isEmpty() && authorities.
iterator().next().getAuthority().equals(StandardAuthorities.USER));
}
private User getComplexInitializedUser() {
User user = new User();
user.setId(1L);
user.setEmail("root@example.com");
return user;
}

Above, we can see that a User comes with a state and is initialized and ready. Still we are able to peek at the
wrapper functionality flow and verify the return values and the underlying component usage.

Now spies offer little added value compared to mocks when a system has a nice, testable design, but when its
is something you dont want to look at design wise, they are really handy. Just dont allow them to get you too
deep and start testing objects youre spying on.

All rights reserved. 2013 ZeroTurnaround O 26


Working with ranges of values: argument matchers and captors
Two other features that allow you an even more fine-grained verification of UserService userService = mock(UserService.class);
User user = mock(User.class);
the things happening to the objects you test are argument matchers and
when(userService.findByEmail(anyString())).thenReturn(user);
captors. this.service = userService;
this.validator = new EmailUniqueValidator().
The argument matcher concept is quite straightforward: instead setUserService(service);
of specifying an exact value of the argument, like we did in the }
@After
EmailUniqueValidatorTest, we can specify a range of the arguments.
public void verifyServiceCall() {
verify(service).findByEmail(anyString());
Matchers.any(Class<T> clazz) // any object or null, clazz is used }
to avoid casting @Test
Matchers.anyInt() // any int public void testNonUniqueEmailIsNotValid() {
Matchers.anyString() // any value of String boolean valid = validator.isValid("anything", null);
assertFalse("email is valid despite there's a user with it",
The methods above allow us to conveniently specify a range of valid);
}
possible values to the stubbed method. We could have rewritten
}
testUniqueEmailIsValid using them like shown here.
As you see, we do not restrict stubbing method calls to a specific email. This
@RunWith(MockitoJUnitRunner.class)
public class EmailUniqueValidatorTest extends TestCase { is especially useful, when you want to prepare your mocks for the whole
private EmailUniqueValidator validator; test case, not just for a single test. After every test we make sure that our
private UserService service;
mock was indeed useful and was called with some string parameter.
@Before
public void initialize(){

All rights reserved. 2013 ZeroTurnaround O 27


So while argument matchers provide a convenient way to increase the range of this.service = userService;
this.validator = new EmailUniqueValidator().
accepted arguments, captors serve the opposite goal. With an argument captor,
setUserService(service);
you can verify arguments that were given during the test execution. Look at }
the EmailUniqueValidatorTestMatchers, we use a captor to ensure that the @After
public void verifyServiceCall() {
argument given to the underlying service is in fact a specific value.
verify(service).findByEmail(anyString());
assertTrue(message.equals(captor.getValue()));
@Before
}
public void initialize(){
UserService userService = mock(UserService.class);
User user = mock(User.class); The most useful thing about the captors approach is that you dont
this.captor = ArgumentCaptor.forClass(String.class); need to provide a valid value to verify, but you extract the value and
when(userService.findByEmail(captor.capture())).thenReturn(user);
can validate it in a procedure more complex than a simple comparison.

Verifying the order of calls


The last feature that we want to cover is execution order verification. This example shows a piece of code that does exactly that, first daoMock
It is a very straightforward, but powerful concept that lets you run a should fetch, then validateData. If those methods were called in any
verification of certain method calls happening in an appropriate order. other order, the test will not pass.

For example, you want to fetch a record from the database first and then Simply put, Mockito is a very rich framework and offers many useful
check its data, not the other way around. Mockito offers you an InOrder features, and when you are armed with the ones we showed above, you
interface. can build readable tests for systems of any complexity. Have fun!

import static org.mockito.Mockito.inOrder;



public void verifyDatabaseInteractions() {
InOrder inOrder = inOrder(daoMock);
inOrder.verify(daoMock).fetch(recordId);
inOrder.verify(daoMock).validateData(record);
}

All rights reserved. 2013 ZeroTurnaround O 28


TOO LONG,
DIDN'T READ (TL;DR)
SUMMARY, CONCLUSION, FAREWELL
AND A COMIC

All rights reserved. 2013 ZeroTurnaround O 29


We covered a lot of topics in this report in the context of unit testing an. We
hoped that you got some pointers on the tools available and the capabilities
they offer. For those of you who didnt have time to really delve into it all,
heres a quick sum up:

Keeping Your Code Safe with Unit Testing introduced the concept
of unit testing and the reasons why you and your development team
should be using these methods and tools.

JUnit and TestNG for Advanced Guru-types (deep breath!) covers


JUnit setup and tear-down, parameterized tests, exception testing,
method rules, categories, theories, Test NG feature comparison with http://xkcd.com/1163/
JUnit, super-powered parameterized tests with TestNG and parallel
testing without external support.
To conclude, its pretty clear that Unit Testing with JUnit, TestNG
Figuring out WHAT to test helps you figure out what NOT to test and Mockito brings tangible benefits: a cleaner, better code base,
(like your own database!) and where you should focus your efforts greater involvement and understanding of the code on behalf of your
instead. development and a focus on the big picture all helps you build and
release future versions of your apps much better.
Setting Up Mock Alternate Realities helps you know when to,
and when not to, use a mocking framework, like Mockito, EasyMock And before we sign off for now, here is some food for thought: How would
and JMockit, to virtually test commands that could have serious you integrate your unit tests in the build process so that the build itself
ramifications if actually carried out in the real world (i.e. print all 50M fails when a test fails? Hint: we already mentioned Integration Tests in
customer invoices!) this report, but for more on that stay tuned!

Mockito for Advanced Users (woohoo!) reviews how to create your


first mocks, why mocking with poorly designed or legacy systems can
give you headaches, a bit about argument matchers, captors and
execution order verification.

All rights reserved. 2013 ZeroTurnaround O 30


This report was
sponsored by:

All rights reserved. 2013 ZeroTurnaround O 31


o n t e n t
c h & c
r e s r
ea around
i s t h e T u r n
l L ab s f Z er o
be
R e divis i o n o
t Us
Co ntac
Twitter: @RebelLabs
Web: http://zeroturnaround.com/rebellabs
Email: labs@zeroturnaround.com

Estonia USA Czech Republic This report is brought to you by:


likooli 2, 5th floor 545 Boylston St., 4th flr. Osadn 35 - Building B Kostis Kapelonis, Oleg elajev, Silver Holmar,
Tartu, Estonia, 51003 Boston, MA, USA, 02116 Prague, Czech Republic 170 00 Ryan St. James & Oliver White
Phone: +372 740 4533 Phone: 1(857)277-1199 Phone: +372 740 4533
All rights reserved. 2013 ZeroTurnaround O 32

Das könnte Ihnen auch gefallen