Tomek Kaczanowski - Practical Unit Testing With Testng and Mockito - 2012
Tomek Kaczanowski - Practical Unit Testing With Testng and Mockito - 2012
Dedication
To my wife, Agnieszka, for all her support, and for having faith that I would eventually finish the book.
Table of Contents
About the Author ................................................................................................................................ vii
Acknowledgments .............................................................................................................................. viii
Preface ................................................................................................................................................... x
I. Developers' Tests ............................................................................................................................... 1
1. On Tests and Tools .................................................................................................................. 2
1.1. An Object-Oriented System ........................................................................................... 2
1.2. Types of Developers' Tests ............................................................................................ 3
1.3. Verification and Design ................................................................................................. 7
1.4. But Should Developers Test Their Own Code?! ........................................................... 8
1.5. Tools Introduction .......................................................................................................... 9
2. Unit Tests ................................................................................................................................ 13
2.1. What is a Unit Test? .................................................................................................... 13
2.2. Interactions in Unit Tests ............................................................................................ 14
II. Writing Unit Tests ......................................................................................................................... 18
3. Unit Tests with no Collaborators ........................................................................................... 19
3.1. Project Structure and Naming Conventions ................................................................ 19
3.2. Class To Test ............................................................................................................... 20
3.3. Your First TestNG Test ............................................................................................... 21
3.4. TestNG Assertions ....................................................................................................... 22
3.5. Failing Test .................................................................................................................. 24
3.6. Parametrized Tests ....................................................................................................... 25
3.7. Checking Expected Exceptions ................................................................................... 29
3.8. Test Fixture Setting ..................................................................................................... 31
3.9. Phases of a Unit Test .................................................................................................. 34
3.10. Conclusions ................................................................................................................ 35
3.11. Exercises .................................................................................................................... 37
4. Test Driven Development ....................................................................................................... 40
4.1. When to Write Tests? .................................................................................................. 40
4.2. TDD Rhythm ............................................................................................................... 42
4.3. Benefits ........................................................................................................................ 48
4.4. TDD is Not Only about Unit Tests ............................................................................. 48
4.5. Test First Example ....................................................................................................... 49
4.6. Conclusions and Comments ........................................................................................ 57
4.7. How to Start Coding TDD .......................................................................................... 58
4.8. When not To Use Test-First? ...................................................................................... 59
4.9. Should I Follow It Blindly? ......................................................................................... 60
4.10. Exercises .................................................................................................................... 63
5. Mocks, Stubs, Test Spies ........................................................................................................ 65
5.1. Introducing Mockito .................................................................................................... 65
5.2. Types of Test Double .................................................................................................. 72
5.3. Putting it All Together ................................................................................................. 77
5.4. Example: TDD with Test Doubles .............................................................................. 79
5.5. Always Use Test Doubles or Maybe Not? .............................................................. 90
5.6. Conclusions (with a Warning) ..................................................................................... 95
5.7. Exercises ...................................................................................................................... 97
III. Hints and Discussions ................................................................................................................... 99
6. Things You Should Know .................................................................................................... 100
ii
iii
100
104
104
109
110
113
115
118
122
128
129
131
134
134
138
147
150
154
163
167
169
170
171
171
174
176
183
185
185
186
186
188
190
190
191
192
196
197
200
204
207
214
216
218
219
219
223
223
229
iv
List of Figures
1.1. An OO system abstraction ............................................................................................................. 2
1.2. Scope of a unit test ........................................................................................................................ 4
1.3. Scope of an integration test ........................................................................................................... 5
1.4. Scope of an end-to-end test ........................................................................................................... 5
1.5. The cost of bug fixing ................................................................................................................... 9
2.1. Types of collaboration with an SUT ........................................................................................... 14
2.2. Is this storage working correctly or not? ..................................................................................... 17
3.1. Results of a test with and without data provider ......................................................................... 26
4.1. The most important picture ......................................................................................................... 42
4.2. TDD rhythm explained ................................................................................................................ 43
4.3. TDD on different levels .............................................................................................................. 49
5.1. Test doubles covering inputs and outputs ................................................................................... 72
5.2. Interactions of Messenger with the test class and DOCs ............................................................ 74
6.1. Excel data file (created with LibreOffice) ................................................................................. 128
8.1. Eclipse: passed tests .................................................................................................................. 172
8.2. Eclipse: failed tests .................................................................................................................... 172
8.3. IntelliJ IDEA: passed tests ........................................................................................................ 173
8.4. IntelliJ IDEA: passed tests - customized view .......................................................................... 173
8.5. IntelliJ IDEA: failed tests .......................................................................................................... 174
8.6. Additional information included within the HTML report ........................................................ 176
8.7. Sample output of the ExcelReporter ......................................................................................... 177
11.1. Code coverage - packages overview ....................................................................................... 244
11.2. Code coverage - single package .............................................................................................. 244
11.3. Single class coverage ............................................................................................................... 245
11.4. 100% code coverage - isnt that great? ................................................................................... 251
11.5. Mutation testing - PIT report ................................................................................................... 252
B.1. Running a single test with Eclipse ........................................................................................... 276
B.2. Running multiple tests with Eclipse ......................................................................................... 276
B.3. Running a single test with IntelliJ IDEA .................................................................................. 277
B.4. Running multiple tests with IntelliJ IDEA ............................................................................... 277
List of Tables
1.1. Types of test example .................................................................................................................... 6
1.2. Examples of SUT and DOC .......................................................................................................... 6
2.1. Types of collaboration with an SUT within test code ................................................................. 14
2.2. Collaborations within the calculateBonus() method .................................................................... 15
3.1. TestNG assertions ........................................................................................................................ 23
3.2. Test fixture examples .................................................................................................................. 32
3.3. Phases of a unit test ..................................................................................................................... 35
3.4. The phases of ClientTest ............................................................................................................. 35
4.1. Expected outputs of regex method .............................................................................................. 63
5.1. Types of test doubles ................................................................................................................... 72
6.1. Comparison of default TestNG assertions and FEST matchers ................................................ 110
7.1. Issues with the random values of parameters ............................................................................ 137
7.2. Arguments for using only one assert per test ............................................................................ 149
7.3. Comparison of new operator testing approaches ....................................................................... 162
8.1. Methods of the ITestListener class ............................................................................................ 179
8.2. Comparison of assertion failure messages ................................................................................. 184
9.1. Examples of test method names ................................................................................................ 195
9.2. @Before and @After annotations ............................................................................................. 204
9.3. Two approaches to test fixture creation .................................................................................... 206
10.1. Comparison of two approaches to testing ............................................................................... 222
11.1. Tests required to obtain 100% coverage ................................................................................. 243
vi
vii
Acknowledgments
In various different ways a number of people have helped me with writing this book some by giving
feedback, others by comforting me in times of doubt.
Marcin Stachniuk was the first person to offer to review the book in the early stages of its being written,
and at the same time the most persistent of my reviewers. He read every part of the book and gallantly
overcame the obstacles I frequently put in his way: frequent releases, constant juggling of the contents,
minor piecemeal adjustments, etc.
Piotr Przybylak helped a lot by introducing me to the concept of "personas".
Michal Margiel read the whole book and sent me a long list of defects he had identified. Some of his
remarks regarding code style were very pertinent, and after I had introduced them the book seemed far
better than before!
Pawel Lipinski, Marcin Zajaczkowski, Pawel Wesolowski, Rafal Janik, Daniel Longosz and Krzysztof
Jelski also contributed by verifying several sections of the book.
Szczepan Faber, Mockitos author, has given me a good bashing, unearthing several weaknesses in the
book as it went along, but at the same time has appreciated my work and encouraged me to go on with it.
Jakub Naruszewicz and Shamil Daghestani helped preparing Kindle version of the book.
I have also received a great deal of encouragement from Java community members on social networks.
Thanks to all of you!
This book would never have happened if it had not been for the (unwitting) help of thousands of bloggers
and mailing group debaters. I have learned a lot from, and have been inspired by, numerous Java, PHP,
Ruby and .Net articles, blog posts and discussions. It is amazing to find out that despite the differences
in tools and approaches, so many of us share the same ideals of clean, perfect code, and that we also
rack our brains about similar issues.
I have also learned a considerable amount from the participants in training sessions that I myself have
conducted. By sharing their doubts and comments with me, they have helped me to rethink my stances
and look for even better solutions, approaches or tools.
My colleagues at work have given me much food for thought, just by doing things differently from how
I would, while insisting that their way is better! :) This has also helped me go forwards, even if Ive
sometimes had to take a few steps backwards first!
Carl Humphries has done a splendid job by translating this book from my version of English into a
standard one. You would not enjoy reading this book at all, were it not for his hard work!
My gratitude also goes out to the authors, contributors and community members of all of the numerous
fantastic free tools, libraries and applications I have made use of while writing it. My deepest respect goes
to everyone who contributed even a single line of code to the following projects: AsciiDoc, Docbook,
vim, Apache FOP, xlstproc, Subversion, IntelliJ IDEA, FoxitReader, Calibre, EPUB Reader, Inkscape,
Gimp, ImageMagick, LibreOffice, PCLinux OS, various bash tools (grep, diff, tree, etc.), xmind.net,
toodledo.com, clker.com, wikipedia.org, stackoverflow.com, xp-dev.com and github.com. I would also
like to thank all the people on the AsciiDoc and Docbook mailing lists for bearing with me, even when
my questions seemed foolish.
Even though many people have contributed to this book and have carried out reviews, all
bugs still belong to me!
viii
Acknowledgments
My family has also made an immense contribution. Agnieszka, my wife, has supported my work from
the very beginning, repeatedly reminding me about the need to focus on getting things finished, and
giving up some of her so-called "free-time" so that I could have more time to spend on it. Without her
help, I would simply have never finished the book!
My daughters - Zosia and Helenka - gave me reasons to smile every day; something I needed very much,
being tired and depressed with the amount of work still lying before me.
Our cat - Boni - has played a double game. Some evenings she helped me to calm down by sitting on
my lap, purring softly, while sometimes she deprived me of sleep by making an awful racket at night! :)
ix
Preface
Times are bad. Children no longer obey their parents, and everyone is writing a book.
Cicero
Preface
Vocabulary
I have tried to follow the naming conventions introduced by [meszaros2007]. As far as I know, the
terms he introduced (or gave definitions for) have "caught on" within the developer community, and are
currently in use by most developers.
Exercises
Tell me and I forget. Teach me and I remember. Involve me and I learn.
Benjamin Franklin
Most sections of the book contain some exercises. Remember, they are there to be done, not to be read!
No excuses! ;)
Preface
Some method names have had to be shortened as otherwise they would not have been correctly
wrapped in the PDF version of the book. This is a shame, as I was really attached to them. :)
Icons
The following icons appear within the text:
A helpful tip.
An additional note.
Book Site
The official book site is on http://practicalunittesting.com. Please visit it for news and information on
downloadable extras etc.
Code Download
All examples from the book (including exercises) are available online. Please visit http://
practicalunittesting.com for detailed information on how to acquire them.
Piracy
I guess the book is already out there. Well, I take that as a compliment: apparently it must be worth
stealing. But of course, you wont be left with that nasty taste in your mouth if you buy it rather than
stealing it!
xii
Naming Chaos
If you start digging into the topic of tests, you will be amazed at how many names show up. Unit tests,
integration tests, smoke tests, stress tests, end-to-end tests, exploratory tests, system tests, performance
tests, user tests, automated tests, acceptance tests, etc. You may well feel perplexed by the sheer number
of them, and by the variety of existing classifications. You will get even more perplexed if you start
looking for a definition for each of them. Soon you will come across a good few definitions of the same
term that differ substantially1. This terminological chaos makes testing subjects much harder to follow
than they should be.
In this book I follow what I regard as being the most widely used set of test-related terms. I think, that
the chosen names describe their purpose well. I can only hope that they do so for you too.
Yes, that is it! A bunch of circles and arrows. Circles are objects, arrows are messages being passed
between them. As you can see, we also have a client in this picture, and his action (his request) has
initiated a great deal of activity in our OO system. Why so many objects, and so many messages, out
1
Alas, even though some terms seem to have a well-established meaning, they still often get to be misused.
See http://en.wikipedia.org/wiki/Object-oriented_programming for more information.
See http://en.wikipedia.org/wiki/Object-relational_mapping
See http://en.wikipedia.org/wiki/Dependency_injection
Not every test run with a unit testing framework is a unit test! Make sure that your unit tests
conform to the definition presented in Section 2.1!
Test doubles are fake replacements of real parts of the system (e.g. classes or modules). This topic will be discussed in detail in
Chapter 5, Mocks, Stubs, Test Spies.
As Figure 1.3 shows, integration tests usually extend across a few layers (e.g. when testing whether your
services work correctly with a DAO layer). They execute code written by your team, but also code from
third-party libraries used by the tested application. As with unit tests, vast areas of the system are either
not touched by integration tests or are replaced by test doubles. Integration tests usually do not touch
the user interface (the GUI). Because of this, the client (user of the system) is not shown in the picture.
Figure 1.4 shows an end-to-end test that puts to the test elements from all layers - from the front end
(GUI, web services layer or any other external API of the tested system) to the storage layers (e.g.
database storage). End-to-end tests are initiated through a request identical to those issued by real users
of the system (e.g. clicks on GUI elements).
5
1.2.4. Examples
Table 1.1 gives examples of each type of tests.
test examples
unit test
An object of the class FootballPlayer should change its status to fired after
receiving a second yellow card.
A constructor of the class Product should throw an IllegalArgumentException
(with meaningful message) if the price argument is less than 0.
integration
test
end-to-end
test
A logged on user can add comments to any public picture by clicking on the
add comment button next to it. Guest users (users not logged on) can see
this comment after it is published, but cannot post their own comments.
When a shop owner adds a new product to his shop using an Add Product
form, it will be possible to locate this product using a Search Form by entering
its name in the search field.
When a user sends his/her geo-location data using a whatCityIsThis web
service, the system should respond with a city name.
Table 1.2 presents examples of SUTs and DOCs for each type of test. It shows how SUTs and DOCs
"grow" when moving from unit tests (smaller), via integration tests (medium), to end-to-end tests (large).
The difference in granularity is clearly visible. In the case of unit tests, the SUTs and DOCs are simply
classes. Integration tests act at the level of modules or layers. In the case of end-to-end tests, it is the
whole application that is tested (making the application itself into an SUT), and other applications are
collaborators (DOCs).
integration test
SUT example
DOC example
UserService
UserDAO
Invoice
Product
Client
Account
Hibernate
MySQL 5
FullTextIndexer module
FileStorage module
6
SUT example
end-to-end test
Whole application
DOC example
External web service(s)
LDAP repository
1.2.5. Conclusions
All of the types of test presented in the preceding sections are important. From the point of view of a
development team, each of them will have its own value. Unit tests help to ensure high-quality code,
integration tests verify that different modules are cooperating effectively, while end-to-end tests put the
system through its paces in ways that reflect the standpoint of users. Depending on the type of application
you are implementing, some of them may be more suitable than others.
Another way to think about the various types of test is to place them on an scale. At one end of this
scale are unit tests, whose role is just to check whether we are implementing a given system correctly.
At the other are end-to-end tests, whose main purpose is to verify that we are implementing the right
system. Integration tests lie somewhere between.
This book concentrates on unit tests, only to a very limited extent touching on other kinds of test.
However, it is very important to be aware of their existence, and not to rely solely on unit tests. Unit
tests are the foundation of developers tests, but rarely are they sufficient in themselves. Please bear this
in mind as you learn about unit tests.
So which tests should you write for your application? Alas, there is no easy answer to this
question. No golden rule exists, which would describe the right proportion of tests of different
kinds. It depends to a very high degree on the type of application you are writing.
By legacy code I mean any code without tests (i.e. unit tests).
http://stackoverflow.com
Developers tests are the first line of defense against bugs. They kill them as soon as they appear. Of
course, for the reasons mentioned at the beginning of this section, some bugs will probably make it
through. Well, yes, it might just happen! That is why other lines of defense have to be in place, too: i.e.
highly skilled, specialized testers. Hopefully they will hunt down all the remaining bugs8.
In fact, many companies rely (almost) solely on developers tests. Big names like Facebook
or WordPress adopt a continuous deployment approach, which can be summarized as "if
it has passed the automatic tests it goes into production". No human testing involved! So it
is possible after all, isnt it?
So, should developers tests their own code? Oh yes, they should!
and if you disagree, please stop reading now.
10
10
Other Tools
It would be simplistic to say that everything other than the testing framework and mock library plays
a secondary role. If you master writing unit tests, you will find good uses for many more tools. Here
are my choices.
12
13
Two interactions are direct, and involve the SUT and its client (a test class, in this case). These two are
very easy to act upon - they are directly "available" from within the test code. Two other interactions are
indirect: they involve the SUT and DOCs. In this case, the client (a test class) has no way of directly
controlling the interactions.
Another possible classification divides up interactions into inputs (the SUT receiving some message)
and outputs (the SUT sending a message). When testing, we will use direct and indirect inputs to set
the SUT in a required state and to invoke its methods. The direct and indirect outputs of the SUT are
expressions of the SUTs behaviour; this means we shall use them to verify whether the SUT is working
properly.
Table 2.1 summarizes the types of possible collaboration between an SUT and DOCs. The first column
"type of interaction" describes the type of collaboration from the SUTs point of view. A test class
acts as a client (someone who uses the SUT); hence its appearance in the "involved parties" column.
involved parties
description
direct input
direct output
indirect output
indirect input
An SUT is a thing being tested; DOCs are its collaborators. Both terms are introduced in Section 1.2.
14
Listing 2.1. Example class to present various types of interaction in unit tests
public class FinancialService {
.... // definition of fields and other methods omitted
public BigDecimal calculateBonus(long clientId, BigDecimal payment) {
Short clientType = clientDAO.getClientType(clientId);
BigDecimal bonus = calculator.calculateBonus(clientType, payment);
clientDAO.saveBonusHistory(clientId, bonus);
return bonus;
}
}
As you can see the SUTs calculateBonus() method takes two parameters (clientId and payment)
and interacts with two collaborators (clientDAO and calculator). In order to test the calculateBonus()
method thoroughly, we need to control both the input parameters (direct inputs) and the messages
returned from its collaborators (indirect inputs). Then we will be able to see if returned value (direct
output) is correct.
Table 2.2 summarizes the types of interaction that happen within the calculateBonus() method, and that
are important from the test point of view.
involved parties
direct input
direct output
indirect output
indirect input
description
clientType
calculator
In fact, it would be more correct to say that access to one storage area is cheaper than to the other one. Usually, the unit of cost is
time-relative, so we will make such a simplification here.
3
Requirements 2a and 2b could also be expressed as follows: "first search in the cache storage, then in the main storage".
4
Which basically means that most of the items will be in the cache when requested, and the number of queries to the real storage
will be minimized.
16
Ideally, when a request comes first the cache storage is searched and then, in case the cache storage does
not have an entry with the given key (X in this example), the main storage is searched. However, if the
SUT is not implemented correctly then it can first look into the main storage without checking the faster
storage first. The client who waits for an object with the given key can not distinguish between these
two situations. All he knows is that he requested an object with key X and that he got it.
In order to really verify whether our system is working as it is supposed to or not, interaction testing
must by applied. The order of calls to collaborators cache and real storage must be checked. Without
this, we cannot say whether the system is working or not.
This simple example proves that verification of the observable behaviour of the SUT (its direct outputs)
is not enough. Similar issues arise when testing managers (see Section 1.1), which coordinate the the
efforts of others. As mentioned previously, such coordinating classes are quite popular in OO systems.
This is why we will be spending a great deal of time discussing techniques, tools and issues related to
indirect outputs testing.
But to begin with lets concentrate on the simpler case. In the next section we will learn how to test
simple objects that do not have any collaborators.
17
As you can see, the Money class is immutable. It has two final fields set by the constructor. The only
method with some logic is the implementation of equals().
1
20
annotation is required, so TestNG (and other tools) will recognize this class as a test class.
The static import of the Assert class method(s) makes assertion checking more concise.
@Test annotation used at class level signifies that all public methods of this class count as test
methods5.
The test class does not have to extend any base class or implement any interfaces. Its name is also
not important, though using the Test suffix leaves no doubt as to its purpose.
The test method can take any name.
An SUT is created.
The SUT is put to the test and the results are verified using the static assertEquals() methods of
the Assert class.
@Test
That is quite a lot of information for such a simple class! Much more could be written about each line
of this code, but that is enough for now. We will discuss it step by step in the course of considering
subsequent examples. Let us run the test now.
4
It is questionable whether such code is worth testing in code-first manner. Please see the discussion in Section 10.5.
Please see Section 9.2 for additional information.
21
Remember to always look at the status line and react immediately if you see failed or skipped tests.
Also, take note of the number of tests executed. It can happen, especially at the beginning of your testing
journey, that your test will not run at all!
Table 3.1 shows all of the assertion methods of the org.testng.Assert class. Most of the methods
displayed come in multiple variants with different parameters (e.g. assertEquals() accepts two
parameters of type boolean, double, String, Set, and others, too). Please refer to TestNG Javadocs for
detailed information on available assertion methods.
description
assertTrue()
assertFalse()
assertNull()
assertNotNull()
assertEquals()
assertNotEquals()
Uses the equals() method to verify that objects are not identical.
assertEqualsNoOrder()
Checks if two arrays contain the same objects, but does not care
about the ordera.
assertSame()
assertNotSame()
If you also want to verify the order, use the assertEquals(Object[] actual, Object[] expected) method.
Some of the above methods (e.g. assertTrue(), assertNotNull()) take only one parameter and an
optional message (see Section 3.5). Others e.g. assertEquals() and assertSame() take two
parameters and an optional message. In such a case, the order of parameters is the following:
1. actual value,
2. expected value,
3. (optional) message.
This order might be quite surprising for users of JUnit, as it uses quite the opposite order of
actual and expected values. If you are addicted to JUnits assertions you can still use them
with TestNG. Simply import org.testng.AssertJUnit instead of org.testng.Assert.
You might ask what difference the order of the first two parameters makes. Is there any difference
between comparing A to B and comparing B to A? Of course, there is no difference in terms of result.
They are the same/equal, or they are not, right? You will notice the difference only when the test fails.
We will get to that soon.
Another point is that you should really learn all of the above assertions and make use of them. At first you
might be tempted to stick with just the simplest: i.e. assertTrue() and assertFalse(). They will allow
you to verify just about anything, provided that you write a condition which evaluates to true or false.
True, but verifying results with assertSame(), assertNull() or assertNotEquals() will make your test
code much more readable. Remember, "use the right tool for the job"! This holds on every level.
23
org.testng.Assert.fail(Assert.java:89)
org.testng.Assert.failNotEquals(Assert.java:480)
org.testng.Assert.assertEquals(Assert.java:118)
org.testng.Assert.assertEquals(Assert.java:365)
org.testng.Assert.assertEquals(Assert.java:375)
com.practicalunittesting
.MoneyTest.constructorShouldSetAmountAndCurrency(MoneyTest.java:18)
One thing we should notice is that the order of assertions' parameters is really important. The printed
information about the reason for the test failure is based on the assumption that we kept to the default
order (remember: first actual value, then expected value). In any other circumstances, the printed
information would have been misleading.
We will discuss the assertions' messages in details in Section 8.4.
24
Money
10 USD,
Listing 3.8. Testing the Money class with 10 USD and 20 EUR
public void constructorShouldSetAmountAndCurrency() {
Money money = new Money(10, "USD");
assertEquals(money.getAmount(), 10);
assertEquals(money.getCurrency(), "USD");
money = new Money(20, "EUR");
assertEquals(money.getAmount(), 20);
assertEquals(money.getCurrency(), "EUR");
}
This approach will work, but its drawbacks are clearly visible. First of all, there is a lot of repetition and
a clear violation of the DRY7 principle. Secondly, such code is usually created using the "copy&paste"
technique, which is a sure recipe for getting into trouble by copying the whole section while only
changing a part of it. Thirdly, the test class will grow with every new set of arguments. Enough! There
must be a better way!
You can use various techniques to avoid repetitions such as those presented above. For example,
you could introduce a for loop. That would make it better, but at the same time would result in the
introduction of logic into your test (albeit of a very basic kind), which is not advisable (see Section 10.2).
You could also divide the constructorShouldSetAmountAndCurrency() method into a number of smaller
methods, each checking only one set of parameters. Yes, but that would have similar unwanted features
to those of the naive approach discussed previously.
We will discuss the problem of what values should be verified in Section 6.1.
See http://en.wikipedia.org/wiki/Dont_repeat_yourself.
25
The @DataProvider annotation means, that the getMoney() method will provide argument values
which will be used as arguments for some of the test methods.
Data providers are expected to return an Object[][] array.
The constructorShouldSetAmountAndCurrency() method expects two parameters: amount and
currency. Each row of the array returned by the data provider contains them both.
The first set of arguments will consists of the number 10 and the currency USD.
The second set of arguments will consists of the number 20 and the currency EUR.
If a method uses the data provider, it will have to be annotated with a @Test annotation with the
dataProvider attribute.
Instead of hardcoded values both arguments are used to create an object of the Money class and
to verify it.
If you run the test on Listing 3.9, you will notice that TestNG has created two test cases "under the
hood", and now it reports that two tests have been executed. What is more important, you will receive
detailed information about what happened: i.e. what values were used for each test. Figure 3.1 compares
the output of the two test: MoneyTest from Listing 3.8 and MoneyDataProviderTest from Listing 3.98.
With respect to MoneyTest, all you know is that the test passed. As regards MoneyDataProviderTest, you
also know what parameters were involved. In the case of a successful test run this might not be a big
deal, but in the case of a failure you will instantly know what combination of data caused it.
We have not yet discussed the test reports which are covered in Chapter 8, Getting Feedback.
26
The implementation of such a scenario would also require the use of a skipFailedInvocations attribute of the @Test
annotation. Please refer to the TestNG documentation for details.
28
3.6.5. Conclusions
Summing up, the advantages of using data providers over any custom code are the following:
none of ones own, potentially flawed, logic is introduced (e.g. for loop),
adding another set of arguments is very easy, and does not make the code grow,
a single data provider can be used to feed multiple test methods (and can do so across multiple test
classes), making the code even more concise,
there is no copy&paste coding, there are no "global" variables, and the DRY principle is faithfully
honored,
there is a clear separation between test logic (how the code is expected to work) and test data (what
values are tested),
we get more detailed results of the tests execution.
In case your test classes (not test methods!) are parametrized, you should use another feature
of TestNG: factories. Their purpose is to create multiple instances of test classes. A common
use of factories is to run web tests (written with, for example, Selenium) against different web
browsers (Firefox, Opera, Safari, Chrome etc.), or some DAO layer tests against different
databases. Because factories are rarely used in unit tests, we will not discuss them. Please
refer to the TestNG documentation for a detailed description.
The expectedExceptions attribute of the @Test annotation specifies exceptions that are expected
to be thrown by this test. It can take one exception, as in the example above, or many (e.g.
@Test(expectedExceptions = {ExceptionA.class, ExceptionB.class})). In the latter case, the test
method is expected to throw one of the exceptions from the list.
29
amount
is less than 0,
currency
is null or empty.
Now, we would like to test it10. The test can look as shown in Listing 3.15. In this test we used data
providers that you are already familiar with. They make the code very concise and allow for multiple
values to tested without encountering difficulties.
Another thing worth noticing is the lack of assertions in the test methods shown in Listing 3.15. In fact
there is no need to write any code to check whether expected exceptions have occurred. TestNG will
take care of this, on the basis of information contained within the expectedExceptions attribute of the
@Test annotation. So we can say that in fact there is an implicit assertion, or maybe rather an implicit
try-catch statement, added automatically by TestNG.
All of the tests shown in Listing 3.15 are one-liners, but this is only because we dont need
more lines to invoke the constructor of the Money class. Obviously, TestNG does not limit
the length of test methods!
10
Personally, I feel slightly uneasy about this code-first approach. We shall soon be introducing the test-first technique, and will be
adhering to it throughout the rest of the book.
30
By using meaningful names for variables, we have achieved a highly readable test. Just read it: "this
line of code creates a new object of the class Money, using an invalid amount and a valid currency".
All perfectly clear.
More information on expected exceptions testing can be found in Section 6.3.
12
31
unit test
integration
test
resetting the database to the initial state (e.g. so it contains one user with
required privileges whose account can be used to perform tests),
copying of files that will be used during tests,
end-to-end
test
installation of a virtual machine that provides the runtime environment for the
application,
installation (or cleaning to some initial state) of the web server and database
used by the application.
32
void
This test is fine, yet it certainly has a lot of repeated code related to the creation of objects. The client
variable is created in each test method. If only we could have it being created in advance of each test
method being executed Well, it comes as no surprise that such a common concern is addressed by
TestNG.
Named setUp() for historical reasons (JUnit 3.x had a special method setUp() responsible for setting up the test fixture). As
stated before, TestNG does not care about the name, what it responds to are method annotations.
33
The @BeforeMethod annotation makes TestNG execute this method before each test method is
executed.
Objects are only created in one dedicated method.
The order of method execution of code from Listing 3.17 is the following14:
setUp()
afterCreationShouldHaveNoAddress()
setUp()
shouldAllowToAddManyAddresses()
setUp()
shouldAllowToAddAddress()
TestNG offers more similar annotations, which helps to control test fixture creation. They are discussed
in Section 9.7.
In fact, the order of execution of the test methods is not guaranteed. What is guaranteed is that methods annotated with
34
arrange
explanation
creation of all objects (except for the SUT) that are necessary for test
execution
creation of the object whose functionality will be tested, and setting it in
some initial state
act
assert
The first phase relates to the preparation of test fixture (see Section 3.8). As we have already discussed,
this functionality is often (at least partially) contained within utility methods shared by many tests, to
avoid duplication of such set-up code across multiple test classes. You might have noticed that, in the
table above, there is no "cleaning" step (or, to use JUnit nomenclature, tear-down method). Such a step
is rarely used in unit tests where fresh objects are created in the beginning of every test method.
Let us now analyze the ClientTest class which we have been discussing in the previous section. Table
3.4 shows how this test fits into the arrange, act, assert structure.
code example
arrange
act
client.addAddress(addressA);
client.addAddress(addressB);
assert
assertEquals(client.getAddresses().size(), 2);
assertTrue(client.getAddresses().contains(addressA));
assertTrue(client.getAddresses().contains(addressB));
As we have seen in the previous examples, not all of the phases will necessarily be contained within
a test method. For example, in the last version of the ClientTest class that we discussed (see Section
3.8.3), both instances of the Address class were created as private fields, and the SUT (an object of the
Client class) was created within a setUp() method. However, this does not alter the fact that during the
test execution the order of their creation was exactly as shown in Table 3.4.
Opinions are divided within the testing community as to what constitutes an adequate number
of assertions per test method (see Section 7.3 for some discussion of this topic). However, it
is recommended that all assertions within a single test method verify properties of a single
object: the SUT. Asserting on many objects within a single test method is considered bad
practice, and should be avoided!
3.10. Conclusions
In this section you have met TestNG and learned:
35
36
3.11. Exercises
The goal of the exercises presented below is twofold: firstly, they are here to help you get used to the
idea of unit testing your code, and secondly, by carrying them out, you will preserve your knowledge
of TestNG features.
String
Now go ahead and write unit tests (using TestNG framework) which will verify that the method works
properly!
Additional requirements and hints:
think about the possible input parameters (see Section 6.1),
use data providers (see Section 3.6) to make the test code concise,
write tests for expected exceptions (see Section 3.7),
if the method on Listing 3.18 does not work properly, then fix it,
37
3.11.3. HashMap
Write unit tests which will verify the following properties of the java.util.HashMap class:
an object stored with the put() method can be retrieved with the get() method,
adding a second object with the same key results in the old value being replaced ,
the clear() method removes all its content,
the null value can be used as a key,
Additional requirements and hints:
use the appropariate TestNG annotations to create a fresh, empty map before each test method is
called (see Section 3.8),
javadocs of the java.util.HashMap class can be accessed at http://download.oracle.com/javase/6/
docs/api/java/util/HashMap.html.
Templates
Every decent IDE allows you to create custom templates for quickly creating larger code structures. For
the sake of efficient unit testing, you should at least learn how to:
38
Quick Navigation
It is very handy to able to quickly navigate between the production class (e.g. Money) and the
corresponding test classes (e.g. MoneyTest). Find out the proper keyboard shortcut for doing this.
39
It is also called Test Driven Design, which stresses the design aspect of this technique.
40
The next picture - Figure 4.2 - gives some more insight into the TDD rhythm. It shows how you start
with a list of tests, choose one of them, and then follow the red-green-refactor cycle, making sure you
end up with green.
2
If I had to choose one thing that I would like you to remember from this book, it would be this picture!
42
In the following sections we shall discuss each element of the TDD rhythm in details.
Of course, you cannot run the test right after having written it. Why? Because if you truly followed the
"never write code without a failing test" rule, then your test would be using some non-existent classes and
methods. It simply would not be able to compile. So, as part of this first step you will also need to make
the test compile. Usually IDE will make this a breeze, by creating a default (empty) implementation of
classes and methods which are used from the test code.
In reality, writing a failing test might sometimes be more trouble than it is worth. Please refer
to Section 4.9 for a discussion.
This rule says: "Start with something really simple. Implement an obvious
This technique is especially useful if you are stuck. Writing something, even something trivial or of only
minimal importance, might be helpful to overcome this sort of "writers block". When you have doubts
about what tests to write and how the tested method should behave, then making the first step might be
the best thing you can do. Even if the functionality implemented in this way is not so important, you
will at least get some of the pieces of the puzzle (the SUT class and some of its methods) in place. It
might help you to move forward.
An example of writing a simple test case just to get you started would be:
writing a parameter-checking test for a function (no matter what the purpose of the function in question
might be),
or, when writing a parser, starting with the test case of passing an empty String to the parsing method
and receiving null in return3.
In neither case would you touch the main logic (probably quite complex) which is to be tested and
implemented. However, you would end up with some classes and methods that might give you some
3
This example is taken from Ash Kims discussion of TDD techniques on StackOverflow http://stackoverflow.com/
questions/3922258/when-applying-tdd-what-heuristics-do-you-use-to-select-which-test-to-write-next
44
Listen To Your Experience. Probably the most valuable way to deal with the "next test" dilemma
is to listen to your experience. It should tell you which one of the above approaches is the most suitable
for this particular case. Personally, I like to go with the typical cases first, but it happens that I use other
approaches as well.
46
Adding Javadocs
During a refactoring phase I will also be taking care of Javadocs - both for production code and tests.
This raises two issues:
1. First of all, your design is still not fixed. Is there a point in writing any documentation now, when
the things may still be about to be changed?
2. Writing documentation now can interfere with the flow of thoughts you have. Your brain is already
focusing on the next test to be written. Is it a good idea to interrupt this so-called "flow" and switch
to a different activity?
These valid questions are reinforced by the natural aversion of developers to writing
documentation. This results in postponing the act of its creation which, of course, leads to
there being no documentation at all. This seems really cool in the short term, but is deadly
in the long run.
What I suggest is the following:
6
See Chapter 11, Test Quality for more information on refactoring of the test code.
47
4.3. Benefits
TDD helps with, but does not guarantee, good design & good code. Skill, talent, and
expertise remain necessary.
Esko Luontola
So now you know the theory behind the TDD cycle. Before we move on to a practical example, let us
again list the benefits of this approach:
all of the code is unit tested,
the code is written to satisfy the tests there are no superfluous parts of the code that have been
written just because they "could possibly be useful" or "will surely be required one day" (YAGNI),
writing the smallest amount of code to make the test pass leads to simple solutions (KISS),
thanks to the refactoring phase the code is clean and readable (DRY),
it is easy to go back into the coding, even after interruptions; all you have to do is take the next test
from the list and start the next cycle.
Once you get into a test-first habit, writing any code without failing tests will make you feel
uncomfortable. :)
There is a huge difference between the two loops. A developer will finish many cycles of the inner loop
each day, while one cycle of the outer loop might even take him a few days. However, both are identical
when it comes to the rhythm of work. In both cases you move from red to green, and then you keep
it green while refactoring. This approach to development, based on the TDD method, has also gained
a degree of popularity and even has its own name ATDD, which stands for Acceptance Test Driven
Development.
We will not be spending any more time on this broader use of TDD, but after you have mastered TDD at
the unit-testing level it is advisable to also try it with different types of test. Once again, [freeman2009]
is a must-read.
There might be more of them - i.e. three - if other tests, like integration tests, were also to be taken into account. However, for the
sake of simplicity I have decided to put only two of them on the picture.
49
FootballTeamTest
- somewhere in the
src/test/java/
directory. It
In a more real-life scenario, a team would probably start with 0 games won, and then, based on the results of games played, it would
incrementally adjust its score.
50
It is quite interesting that we get this code "for free". And I am not just referring here to the IDEs being
able to generate it on the basis of the test. Even if we wrote it by hand, it was still hardly an intellectual
challenge! Writing the test might have been demanding, but creating the code was very, very simple.
That is not always the case, but it does often happen like that.
Since the test compiles, and has an assertion which verifies an important functionality belonging to our
class, it is worth running. Once we run it, it fails miserably, with the following message:
org.testng.Assert.fail(Assert.java:89)
org.testng.Assert.failNotEquals(Assert.java:480)
org.testng.Assert.assertEquals(Assert.java:118)
org.testng.Assert.assertEquals(Assert.java:365)
org.testng.Assert.assertEquals(Assert.java:375)
com.practicalunittesting.
constructorShouldSetGamesWon(FootballTeamTest.java:19)
Let us be clear about this a failing test at this point is a good thing. Now we know that our test has
been executed, and that some important functionality is not ready yet. We will implement it till we see
the green light (that is, the test passes).
51
Now, after we have rerun the test, the output will be more informative (stacktrace omitted):
java.lang.AssertionError: 3 games were passed to constructor,
but 0 were returned
Expected :3
Actual
:0
If we ever break our SUT code, so this test fails, the assertion message will tell us precisely what is
wrong and the fix should be easy.
All right then, it is time to move on to the next phase of TDD we should make the test pass now
by fixing the code, of course.
The test should pass now. However, no celebrations yet! This is the time to polish the code, to refactor
and to add comments. No matter how small the changes you have made, rerun the test to make sure that
nothing has accidentally been broken.
52
Listing 4.6. The simplest thing that satisfies the failing test
public class FootballTeam {
public FootballTeam(int gamesWon) {
}
public int getGamesWon() {
return 3;
}
}
This snippet of code really does satisfy the failing test. You could call it an absurdity, but there is wisdom
in this folly. What it does is prove that your test is not good enough to cover a certain functionality. It
says, "Look, your test is so pathetic, that I can make it pass by doing such a silly thing. You need to try
harder.". And it really makes you write more tests.
The next test could, for example, be to verify whether the same test passes with a different number of
games won say, 5 instead of 3. Such a test would obviously fail, and then you would have to make
the code smarter, so it supports both cases.
53
But is It Comparable?
The constructor works fine. Now we can move on to the main problem: that is, to the comparing of
football teams. First of all, we have decided that we are going to use the Comparable interface. This is an
important decision which will influence not only the implementation of this class but also its API and
expected behaviour. If FootballTeam is comparable, then the client can expect that once he has put a few
teams into a collection, he will be able to use the Collections.sort() method to order them. If so, then
there should be a test for this behaviour. The only one I can think of is the following:
54
This is a rather uncommon test: I rarely write tests which use an instanceof operator. However, in this
case it seems legitimate, as it covers an important characteristic of the FootballTeam class, required by
its clients.
Please note the name of the static value passed to the constructor: ANY_NUMBER. That indicates
that this argument is not important. The real value of the argument does not influence the
test in any way.
The test will fail. Your IDE is surely capable of fixing the code. After the IDE has generated the default
implementation of the compareTo() method, the FootballTeam class will look like this:
Comparison Tests
If you are not familiar with the Comparable interface, please take a look at the description of
the Comparable.compareTo() method Javadocs.
Now let us write the first comparison test. The idea is simple: take two teams with different numbers
of wins and compare them.
55
After running, the test will fail. Once again, the error message is cryptic, and needs to be updated. After
it has been changed, the failed tests can print something more informative:
org.testng.Assert.fail(Assert.java:89)
org.testng.Assert.failNotEquals(Assert.java:480)
org.testng.Assert.assertTrue(Assert.java:37)
com.practicalunittesting.FootballTeamTest
.teamsWithMoreMatchesWonShouldBeGreater(FootballTeamTest.java:36)
Let us fix the production code, but do not implement more than the test requires us to! The compareTo()
method shown below is a minimal (reasonable) implementation which will make the test pass:
56
Well, this test passes instantly, because our implementation has already returned 0 in cases of equality.
So, what should we do now? We have definitely skipped one step in the TDD rhythm. We have never
seen this equality test failing, so we do not know why it passes. Is it because the FootballTeam class
really implements the expected behaviour, or is it because our test has been badly written and would
always pass?
For the time being, let us assume that the test is flawless, and that the implementation of FootballTeam
also is. We will come back to this discussion later on, when examining some corner cases of TDD (see
Section 4.9).
Now that we have a safety net of tests we can really refactor the tested method. After having thought
through the matter carefully, we have ended up with much simpler implementation:
The rerunning of the tests now tells us that this implementation satisfies all the requirements (written
in the form of tests) so far.
10
60
First the IDE will suggest creating a client class with a default constructor and this is good!
When it comes to the setAge() and getAge() methods, IntelliJ IDEA will offer two options: to
create a method, or create a getter/setter.
If you choose the second option generating getters and setters IntelliJ IDEA will generate the
following code:
Now, if you run the test, you will see it pass. Oops seems like we have just skipped the first step of
TDD! This code will not only compile, but pass the first test, so you have no chance to see the failing test!
In the case of such trivial code, I would suggest dropping your TDD habits for a minute and believing
that IDE is capable of doing things correctly. However, there is one thing that we have to do. If the test
fails, we will be 100% sure it was executed. But if all we see is a green color, then we have to be certain
about whether it was executed at all. In cases of larger test suits it might be easy to overlook a test that
was not run. So at least make sure your was test actually executed.
Unfortunately, there are some subtler cases, where extra care is required. Remember the tests of the
compareTo() method that we created for the FootballTeam class (see Section 4.5.6)? The default return
value which the IDE put into the compareTo() method was 0. Given that, if we were to compare
two football teams with equal numbers of wins, such a test would pass instantly. The code of the
compareTo() method is much more complicated than the getters/setters discussed previously, and I would
not recommend taking it for granted that "everything is just fine". Instead, I would suggest the following:
break the code so you see the test fail.
In our case, that would mean changing 0 to some other value, like this:
61
Now rerun the test, and see it fails Good. Revert the change of compareTo() method (so it returns 0
again). Rerun the test to see it pass. Good. This means that your test really verifies this behaviour. And
that is exactly what we wanted to know.
I know this advice might sound extreme, but this is the only way to make sure you do not
make any silly mistakes at all when writing tests.
62
4.10. Exercises
You have just got acquainted with a new development method, which promotes writing tests before
actual implementation. It is time to see, in practice, what you have learned. The exercises in this section
are not so hard from the point of view of the complexity of the tasks. The point is to focus on the
TDD rhythm and not on the algorythmic gotchas. When doing your homework, be extra careful about
following the TDD, and doing everything in really small steps. Good luck!
When working on these exercises, remember to obey the "never write code unless you have
a failing test" rule!
4.10.2. Regex
If you have a problem, which can be solved with regular expression, then you have two
problems.
Wisdom of the Internet ;)
This example requires you to write a method which, given a String, returns a list of all numbers taken
from that String that have 3 or more digits. Table 4.1 gives some examples of expected results for
various input strings.
output
abc 12
cdefg 345 12bb23
345
345, 678
64
See http://docs.codehaus.org/display/GROOVY/Groovy+Mocks
Tools like Mockito are commonly called 'mock frameworks'. This term is slightly misleading, because Mockito is really a test-spy
framework. However, you will hear it used a lot, so you had better get used to this flawed way of referring to it.
3
Other mock-focused frameworks use a slightly different order, which is less friendly, especially if you are a beginner.
2
65
Let us imagine that our SUT uses a DOC of type Car, and that, for the purpose of our tests, we need to
fully control the behaviour of this DOC. Obviously, to be able to use a test double we must first create
it (as mentioned earlier, test doubles are normal Java objects, after all). However, we do not use the
new keyword to bring them to life. Instead, we ask Mockito, or another specialized framework, to create
them. This is shown in Listing 5.2.
This code uses the org.mockito.Mockito class to create a test double. The static mock() method takes a
class as an argument, and returns an object of this class. In the listing above, an object of the Car type
is created. Mockito allows us to create test doubles of both classes and interfaces. If you were to try
checking the type of object created, by means of the instanceOf operator, you would learn that this is
a legal instance of the type Car. Listing 5.3 demonstrates this.
I will be using tests to demonstrate the various capabilities of Mockito.
66
This feature the returning of some default values by test doubles - is specific to Mockito. In fact, this is
just a manifestation of a certain deeper philosophy underlying this tool. Test doubles created by Mockito
are considered to be 'nice', which means their behaviour is not strictly verified (by default). When using
5
For
complete
information
concerning
default
returned
org.mockito.internal.stubbing.defaultanswers package.
67
values
please
refer
to
Mockitos
Javadocs
of
5.1.2. Expectations
Of course, an object which can only return zeros and falseys is not much use to our tests. It is time to
teach our myFerrari object to do as we say.
Let us say we need our myFerrari test double to return true when asked if it needs some fuel. Listing
5.5 shows how this can be done.
This is what we already know - the default return value for the Boolean is false.
Now we tell myFerrari what to do when asked about the fuel. The when() method is another static
method of the org.mockito.Mockito class.
The behaviour has changed. This time myFerrari has returned true. All consecutive executions of
needsFuel() will also return true.
Listing 5.5 also illustrates a very nice feature of Mockito: the fact that code written using it is very
readable. The crucial fragment:
when(myFerrari.needsFuel()).thenReturn(true)
can be read "just like that". Let us try it: "when someone asks myFerrari if it needsFuel() then it should
return true". Voila!
Using a similar syntax, we can also instruct test doubles to throw exceptions. This is shown in Listing 5.6.
This feature of mocking frameworks - throwing exceptions on demand - is extremely useful
for simulating all kinds of errors that can happen during the execution of your application.
It is especially important when testing possible scenarios involving cooperation with some
third-party components - e.g. databases or web services.
68
The test passes, because myFerrari throws the expected exception as instructed.
Expectations set.
This test also passes, as
executed.
myFerrari
needsFuel()
method is
You need to use a different syntax when setting expectations on void methods. This is
discussed in Section 6.4.
5.1.3. Verification
Now we know that using Mockito, we can tell our test double to return some values that are required by
our tests. This is great, and we will be making use of this knowledge very soon. However, for testing
purposes we need something more. We want to make sure that the SUT has executed certain methods
of the DOCs (represented by test doubles). To do this we need to also verify whether some methods of
test doubles have been called. Or, to put it differently, we want to verify the indirect outputs of the SUT.
Watch out now, because this is the moment we enter the world of interactions testing for
real! Up till now, our tests have only mentioned other collaborators. Expectations could
be construed along the lines of "if a certain call to the collaborator happens, then this
collaborator should do X or Y". Now things are different. We are starting to demand
that certain methods of collaborators are executed. This makes our tests very much linked
to the production code, which in turn spells trouble, as it makes them fragile - if the
implementation of the SUT changes, our tests will need to be rewritten. The rule of thumb
to follow here is: write an interactions test only if some of the SUTs features cannot be
tested using state testing.
The first example, shown in Listing 5.7, presents a successful attempt at verification of a test doubles
behaviour. First it invokes some of the methods of myFerrari, then it verifies whether they have been
called. A different, static method of the org.mockito.Mockito class, called verify(), is used to check
the behaviour of myFerrari. The test in Listing 5.7 passes, because the requested methods have really
been invoked.
69
Calling the methods of the test double. Nothing fancy here: no Mockito syntax of any sort, simply
normal method calls
The verification part. Checking has occurred of whether myFerrari has really been asked to drive
to Alabama, and whether someone has requested it to answer a "Do you need fuel?" question.
Once again the code is quite readable: "verify() that myFerrari was asked to drive() to Alabama".
Now let us take a look at another example. This time the expectations are not met. The test is shown
in Listing 5.8.
the getEngineTemperature() method had been expected, but did not occur. Hence the failure.
70
Listing 5.11. The output of failed verification test - arguments do not match
Argument(s) are different! Wanted:
car.driveTo("Sweet home Honolulu");
-> at com.practicalunittesting.FailedVerificationArgumentsTest
.testVerificationFailureArguments(FailedVerificationArgumentsTest.java:22)
Actual invocation has different arguments:
car.driveTo("Sweet home Alabama");
-> at com.practicalunittesting.FailedVerificationArgumentsTest
.testVerificationFailureArguments(FailedVerificationArgumentsTest.java:21)
Readable error messages are one of the selling points of Mockito. This feature is really
important!
5.1.4. Conclusions
So far we have looked at a bit of Mockito, and we know that it can help us to write tests with test doubles.
In particular, Mockito can:
create various test doubles (e.g. Car
myFerrari = Mockito.mock(Car.class)),
when(myFerrari.needsFuel()).thenReturn(true)
when(myFerrari.needsFuel()).thenThrow(new RuntimeException())),
71
or
also known as
description
dummy object
dummy
test stub
stub
test spy
spy
mock object
mock
Figure 5.1 shows how test stubs, test spies and mocks cover a different aspect of communication between
the test class, the SUT and its DOCs.
Fake
For the sake of completeness, let us describe another type of test double: a fake. Fake works
almost as good as the real collaborator, but is somehow simpler and/or weaker (which makes
it not suitable for production use). It is also usually "cheaper" in use (i.e. faster or simpler
to set up), which makes it suited to tests (which should run as fast as possible). A typical
example is an in-memory database that is used instead of a full-blown database server. It can
be used for some tests, as it serves SQL requests pretty well; however, you would not want
to use it in a production environment. In tests, fake plays a similar role to dummy and stub:
it is a part of the environment (test fixture), not an object of verification. Fakes are used in
integration tests rather than in unit tests, so we will not be discussing them any further.
Please refer to Appendix C, Test Spy vs. Mock for a detailed comparison of test spy and mock.
73
Figure 5.2. Interactions of Messenger with the test class and DOCs
Creation of a dummy object. We assign a real object to it, generated using the mock() method.
Execution of the SUTs method using a dummy template object as one of the parameters.
To sum up, a dummy object is required just to execute the test, but not really needed for anything useful.
It simply has "to be there". In some cases null will suffice, but in general it would be more far-sighted
to use a mocking framework to generate an object of the requested type.
You probably will not use dummies a lot. In my experience they are rarely required.
Maybe you have already noticed that it is enough to pass a null value as a template parameter.
That would work, but in general it is not recommended. It is probable that the method being
tested will sooner or later be extended with some arguments checking functionality, so null
values will not be accepted. Then your test will break, which is always frustrating. Instead
75
5.2.5. Mock
I feel I should say at least something about mocks, even though we do not really need them. Let me
repeat that in functional terms, there is little difference between a mock and a test spy. What a test spy
can do, a mock can also do (and vice versa). The difference lies in the syntax and in the flow of code
within your test methods. The main purpose of the mock and the test spy are the same: to verify that
some communication between objects has taken place: i.e. that some methods have been called. I have
decided to devote Appendix C, Test Spy vs. Mock to a detailed discussion of the differences between
test spies and mocks. But this is not something you need to know about. If you have grasped the idea of
test spies, you can write perfect tests without knowing about mocks.
Do not worry that we havent really covered mocks! You can still put in your CV that you
know how to mock classes. This is because mocking is about verifying the collaboration
between the SUT and DOCs, and you are perfectly capable of doing this.
As regards our example, we could use a mock to cover exactly the same area that we decided to use a
test spy for: to verify the expected behaviour of the SUT.
See http://en.wikipedia.org/wiki/Publish/subscribe.
79
This simple test code results in the RaceResultsService class being (auto)generated by the IDE, as shown
in Listing 5.18.
To test the functionality under consideration, we must introduce the two remaining types: Client and
Message. Listing 5.19 shows this next step creating the DOCs.
80
Now it is time to write the actual test. I would like it to present the following functionality:
the client subscribes to the service,
the service sends a message to the subscribed client.
This test is displayed in Listing 5.21.
81
Listing 5.22. Empty implementation of methods required for the first test
public interface Client {
void receive(Message message);
}
public class RaceResultsService {
public void addSubscriber(Client client) {
}
public void send(Message message) {
}
}
The test compiles, so let us run it. The error message as shown in Listing 5.23 - clearly indicates that
the functionality does not work. The client has not received any message.
Listing 5.23. The first test has failed: the client has not received any message
Wanted but not invoked:
client.receive(
Mock for Message, hashCode: 23894119
);
-> at com.practicalunittesting.RaceResultsServiceTest
.subscribedClientShouldReceiveMessage(RaceResultsServiceTest.java:32)
Actually, there were zero interactions with this mock.
Very good! This means we really are into the RED phase of TDD. Following the TDD approach, let
us implement "the simplest thing that works" (see Section 4.2.2) that satisfies the failing test. Listing
5.24 shows such an implementation.
Listing 5.24. The first test has passed: a single subscriber receives a message
public class RaceResultsService {
private Client client;
public void addSubscriber(Client client) {
this.client = client;
}
public void send(Message message) {
client.receive(message);
}
}
Once again, even though I can imagine this code being changed, and can even suspect how it would
be changed (e.g. using a collection of clients instead of a single client field), I do not make use of this
knowledge. Coding it now would be an example of YAGNI. What I really need to do is make the test
pass (move in small steps, remember?). And the implementation shown in Listing 5.24 achieves this
goal. So, for the time being it counts as perfect and does not call for any changes.
The execution of the test assures me that this implementation will be good enough for now.
Before implementing the next test, I spend a bit of time refactoring and making the code more readable.
In the case of the code written so far, there is not much to be done. The classes and interfaces are very
short (no copied code fragments, etc.), and I like the current method and class names. At this point
82
RaceResultsService
Listing 5.25. The second test: messages sent to multiple subscribed clients
@Test
public class RaceResultsServiceFirstAndSecondTest {
public void subscribedClientShouldReceiveMessage() {
RaceResultsService raceResults = new RaceResultsService();
Client client = mock(Client.class);
Message message = mock(Message.class);
raceResults.addSubscriber(client);
raceResults.send(message);
verify(client).receive(message);
}
public void messageShouldBeSentToAllSubscribedClients() {
RaceResultsService raceResults = new RaceResultsService();
Client clientA = mock(Client.class);
Client clientB = mock(Client.class);
Message message = mock(Message.class);
raceResults.addSubscriber(clientA);
raceResults.addSubscriber(clientB);
raceResults.send(message);
verify(clientA).receive(message);
verify(clientB).receive(message);
}
}
The old test (the one verifying the sending of messages to a single subscriber) is left untouched,
even though it seems to be redundant. However, I am going to keep it, so I can always be sure that
this functionality will work for a single subscriber.
The second test verifies whether the service works for more than one subscriber.
In order to implement the new test, I need more test doubles of the Client class.
As in the case of the test discussed earlier (see Listing 5.21), both client objects (clientA and clientB)
are test spies, and message is a dummy.
8
83
Well, obviously the addSubscriber() and send() methods of the RaceResultsService class are not able
to operate on more than one client. A possible fix is shown below.
Listing 5.27. The second test passed: multiple subscribers receive the message
public class RaceResultsService {
private Collection<Client> clients = new ArrayList<Client>();
public void addSubscriber(Client client) {
clients.add(client);
}
public void send(Message message) {
for (Client client : clients) {
client.receive(message);
}
}
}
Refactoring
The production code looks fine, but the test code really calls out to be refactored. There is an obvious
redundancy relating to the creation of the SUT and DOCs in every test method. We can expect that
subsequent test methods will also require a fresh SUT and DOCs, so it seems a good idea to move this
redundant code into a specialized method9. The result of this refactoring is shown below.
We will discuss the issues related to test fixture creation in Section 9.7.
84
RaceResultsService raceResults;
Message message;
Client clientA;
Client clientB;
@BeforeMethod
protected void setUp() {
raceResults = new RaceResultsService();
message = mock(Message.class);
clientA = mock(Client.class);
clientB = mock(Client.class);
}
public void subscribedClientShouldReceiveMessage() {
raceResults.addSubscriber(clientA);
raceResults.send(message);
verify(clientA).receive(message);
}
public void allSubscribedClientsShouldReceiveMessages() {
raceResults.addSubscriber(clientA);
raceResults.addSubscriber(clientB);
raceResults.send(message);
verify(clientA).receive(message);
verify(clientB).receive(message);
}
}
The SUT and all of the DOCs have now been created within the setUp() method, annotated with
@BeforeMethod annotation.
Both test methods are guaranteed to receive all objects (the SUT and all DOCs) in a "fresh" state,
as created by the setUp() method.
Listing 5.29. The third test: clients not subscribed do not receive any messages
public void notSubscribedClientShouldNotReceiveMessage() {
raceResults.send(message);
verify(clientA, never()).receive(message);
verify(clientB, never()).receive(message);
}
Such a test method is possible thanks to the creation of both the SUT and DOCs within the setUp()
method (annotated using @BeforeMethod annotation). This way, the SUT does not remember that
85
I like the new version better. It shows how things are progressing. Good.
86
By default, Mockito verifies that the method has been invoked exactly once.
After running the test, it transpires that our implementation is not behaving as expected (Listing 5.32).
This can be fixed by replacing List with Set within the RaceResultsService class, as shown in Listing
5.33.
A set does not allow for duplicates. The older version - which used a list - did not work properly.
If you want to specify another value, you could use another static method of the Mockito class: times(),
e.g.:
87
Listing 5.34. The fifth test: unsubscribed client stops receiving messages
@Test
public void unsubscribedClientShouldNotReceiveMessages() {
raceResults.addSubscriber(clientA);
raceResults.removeSubscriber(clientA);
raceResults.send(message);
verify(clientA, never()).receive(message);
}
We know that after this line of code clientA should start receiving messages. Our knowledge is
based on other tests (i.e. subscribedClientShouldReceiveMessage()), which verify this behaviour.
but we want the removeSubscriber() method to alter this behaviour (we let IDE auto-generate
this method),
so clientA will not receive any message. Again, this "negative" verification is done using the
never() method.
After we let the IDE create an empty implementation of the removeSubscriber() method of the
RaceResultsService class, the test will fail, as shown in Listing 5.35.
Proper implementation of the removeSubscriber() method is shown in Listing 5.36. Now the test passes.
88
Listing 5.36. The fifth test has passed: client unsubscribes successfully
public class RaceResultsService {
private Collection<Client> clients = new HashSet<Client>();
public void addSubscriber(Client client) {
clients.add(client);
}
public void send(Message message) {
for (Client client : clients) {
client.receive(message);
}
}
public void removeSubscriber(Client client) {
clients.remove(client);
}
}
http://javancss.codehaus.org
89
However, it could still be a very important, useful and necessary test. Nevertheless, it would lack some of the properties of decent
unit tests: namely, short execution time and good error localization.
91
Collaborators are created using Mockitos mock() method. The creation of DOCs is completely
independent from constructor(s) of the Phone class.
In contrast to real objects of the Phone class, test doubles have no idea about how to behave, so we
need to instruct them. This is required for mobile phones (which should return true). For stationary
phones, there is no need to specify a returned value, as mocks created by Mockito return false
by default12.
The code in Listing 5.40 does not differ much from the previously shown Listing 5.39. Constructor
calls, which defined how objects of the Phone class should behave, were replaced with calls to Mockitos
mock() and when() methods.
No Winner So Far
So far, so good. Both approaches seems fine. Using real classes in test code seems to be justified by the
close relationship between Client and Phone. Both test classes are concise and free of any logic. Good.
12
See Section 5.1.1 for information concerning the default behaviour of Mockitos test doubles.
93
Do not do this at home! This is surely not a valid way to recognize mobile phone numbers!
After this change has been introduced, the test, which does not use mocks, needs to be updated. This
time, in order to create appropriate phones (mobile and stationary), a knowledge of the internals of the
Phone class is required. Without it there is no way a developer could construct a phone of the desired
type. The test starts to look as shown in Listing 5.42.
The chosen phone numbers must follow the logic of the Phone's constructor.
This version of the ClientTest class is coupled with the implementation of the Phone class. If the patternmatching mechanism used in the Phone constructor changes, the test code will also need to change.
The SRP principle has clearly been breached, because this test class is also coupled with the Client
class implementation (so ClientTest has more than one reason to change). This is a warning signal.
The violation of SRP entails that the DRY principle has also been breached. Surely, there must exist a
PhoneTest class that will make sure that the Phone constructor and isMobile() method works as expected!
To test this functionality, PhoneTest needs to create identical (or almost identical) instances of phones, as
shown in Listing 5.42. If so, then a change in the Phone class will entail changes in two tests - PhoneTest
and ClientTest. This is bad.
Surprisingly (or, rather perhaps not!), the test class based on test doubles remained unchanged. The
stubs did not even notice the change of algorithm within the Phone class or the difference in the values
of the arguments passed to the constructor, because they do not make use of either of these. They were
ordered to return certain values at certain points of execution, and they are still following those orders.
94
Simple containers for data with getters and setters only. See http://en.wikipedia.org/wiki/Data_transfer_object
Small simple objects like dates, money, strings. See http://c2.com/cgi/wiki?ValueObject
15
Another solution is to extract the DOCs creation parts of the code into some utility method. This solves the problem of multiple
changes, but reduces the readability of test code by forcing the reader to jump between different classes.
14
95
16
See http://en.wikipedia.org/wiki/Information_hiding
96
5.7. Exercises
The exercises presented in this section will allow you to practise your knowledge of testing with test
doubles through actually using them. They will also allow you to familiarize yourself with the Mockito
framework.
should send messages with the results of different categories of race - e.g. horse
races, F1 races, boat-races, etc. Subscribers should be able to subscribe to selected categories. Make
sure they receive only messages related to the ones they have signed up for.
RaceResultsService
Each message sent by RaceResultsService should be logged. Introduce a logging DOC, and make
sure that the date and text of each message is logged. Do not implement the logging mechanism:
concentrate on the interactions between the service and its collaborator.
In the tests implemented so far, RaceResultsService sends only one message. This is unrealistic!
Enhance the tests to ensure that subscribers will receive any number of sent messages.
What should happen if a client that is not subscribed tries to unsubscribe? Make up your mind about
it, write a test which verifies this behaviour, and make RaceResultsService behave accordingly.
17
98
In this case client is someone or something that calls your code, not necessarily a person.
100
Now, let us test the boundary values. What we surely need to check is whether our counter really starts
with 1 and not with 0. So we need to check that:
12
null
101
2011-28-03
2011/04/18
tomorrow
null
(*&$
102
http://en.wikipedia.org/wiki/You_ain%27t_gonna_need_it
See http://en.wikipedia.org/wiki/All-pairs_testing
7
http://java.net/projects/quickcheck/pages/Home
8
http://databene.org/feed4testng.html
6
103
The fail() method is used here if some condition has not been met.
This test will not run if the fail() method has been executed within the
method.
xmlParserAvailable()
To conclude, you will rarely, if ever, find yourself using fail() methods in unit tests. However, in some
circumstances it can be really useful, so it is good to know about its existence. One possible use of the
fail() method is discussed in Section 6.3.
104
Listing 6.3. Phone class constructor throwing the same exception twice
public Phone(String number) {
if (null == number || number.isEmpty()) {
throw new IllegalArgumentException(
"number can not be null or empty");
}
if (number.startsWith("+")) {
throw new IllegalArgumentException(
"plus sign prefix not allowed, number: [" + number + "]");
}
this.number = number;
}
Now imagine a test method that verifies the expected exception thrown by the Phone class constructor.
Relying solely on the exception type (in this case IllegalArgumentException) will not suffice. Listing
6.4 shows how another attribute of @Test annotation can be exploited in order to write correct tests
The term "code smell" was coined by Kent Beck; see http://en.wikipedia.org/wiki/Code_smell for more information.
105
The test methods differ with respect to the data providers used and the expected
message of exception thrown. Both cases involve the same type of expected exception:
IllegalArgumentException. However, one test expects the word "empty" and the other the word
"plus" to appear in the message.
The expectedExceptionMessageRegExp attribute of the @Test annotation takes a regular expression
argument, which affords us great flexibility when we come to specify the expected exception message.
As Listing 6.4 shows, the rule of thumb for this says that we should specify a minimal, but crucial,
fragment of the exception message. This will make your tests less prone to fail in the event of the
exception message being changed.
106
Method to be tested. This verifies an incoming request and throws an exception, or asks a
collaborator - requestProcessor - to process it.
]Now let us assume that we want to check to make sure that if an invalid request arrives, it is NOT
then passed to requestProcessor, and that the appropriate exception is thrown. In such a case we will
need to use a different pattern. One possibility is to follow the normal approach to exceptions handling,
based on a try-catch statement.
While writing this test method I could not figure out a good name for it a name that would describe the scenario being tested.
That is itself a good indication that the scope of what the test is responsible for may be too broad.
107
Importing of static methods of the CatchException class from the catch-exception library.
The static method catchException() of the CatchException class is used to call a method which
is expected to throw an exception.
The thrown exception is returned by another static method (caughtException()). The assertion
verifies whether an appropriate exception has been thrown.
Verification of the absence of any interactions with the requestProcessor collaborator.
The code in Listing 6.7 fits nicely into arrange/act/assert. It is concise and highly readable. The static
methods of the catch-exception library make the sequence of the code easy to grasp. Since the caught
exception is available after it has been thrown (you can assign it to some variable, e.g. Exception e =
caughtException()), it is possible to analyze some of its properties. In addition, if some of the methods
11
See http://code.google.com/p/catch-exception/
108
6.3.4. Conclusions
As this chapter shows, there are many ways to write test code that will verify whether an
expected exception has been thrown or not. For 95% of cases the default TestNG pattern (with the
expectedException attribute of the @Test annotation) is good enough. For the remaining few percent you
can choose between using a try-catch statement and a catch-exception library. Of these two alternatives,
the second one seems more appealing. In fact, if you want to have all your tests share the same pattern
you should consider relying exclusively on the catch-exception library.
To complete the picture, let me also mention that matcher libraries (which are the topic of Section 6.5)
offer many syntactic goodies for writing assertions relating to exceptions. For example, one can replace
the following assertions:
If you find yourself needing to perform such verifications on expected exceptions, consider adding
matchers to your testing toolbox.
However, if a method returns void, then the syntax differs (obviously it does not make sens to return
anything from void method, so in the example below we instruct the voidMethod() to throw an
exception):
109
6.5. Matchers
Up to now we have been almost exclusively using standard TestNG assertions. We have used
assertTrue() to verify some basic boolean expressions, assertEquals() to compare two objects with
respect to equality, and assertNull() or assertNotNull() to make sure that a given object is or is not
null, etc. These basic assertions are enough to verify any condition you might think of. That is true, but
there is still room for further improvement here! In particular, thanks to using matchers we can have
more readable test code, which is always a good thing.
In some sections of this book we have already mentioned that there are two aspects to the readability of
assertions: how they look within the test code, and what information is given to the developer once an
assertion has failed. Matchers are particularly useful for helping with both of these issues.
The information included in this section is valid across all currently existing implementations
of matchers; you can use what you learn here with both FEST and Hamcrest (the two most
popular frameworks of this kind). All the examples will be written with FEST, but only
because this is my tool of choice.
Matchers makes your tests more readable. They provide extra readability at a linguistic level, because
the order of words in assertThat(worker, isA(manager)) resembles natural language much more closely
than does assertEquals(worker, manager), the standard assertEqual() assertion. This is true both for
FEST or Hamcrest matchers available out-of-the box, and for custom matchers that you yourself write.
The following example demonstrates this:
FEST matchers
You may also notice that the use of matchers introduces a specific "rhythm" to your assertions: they
all read similarly.
But so far this is nothing to get especially excited about. We can do more than this by writing custom
matchers, which are designed to verify properties of our domain object. For example, would it not be nice
to replace the assertion on a books title property with a simple assertThat(book).hasTitle(TITLE)?
Absolutely! This is possible, even though creating such a matcher comes at a certain cost. Listing 6.12
shows the code of a custom matcher that will furnish us with the aforementioned hasTitle() method:
110
111
Such simple examples hardly reveal the true power and usefulness of matchers. Custom
matchers excel particularly when working with rich domain objects or complex data
structures.
It is time to list the advantages of matchers, which are numerous:
they enhance code readability,
they help us to write assertions on the right abstraction level,
they help to remove logic from tests (and encapsulate it within the matchers classes),
they are highly reusable, which is very important if your domain objects are complex and are tested
with multiple test scenarios,
many matchers are available directly from matcher libraries - including specific matchers for work
with collections (as shown in Section 6.9) or exceptions (see Section 6.3),
writing custom matchers is a relatively simple task.
In spite of their usefulness, I do not see matchers being used much. I guess the main reasons for this are
lack of knowledge about them, a general reluctance to add yet another library to ones project, and the
cost involved in implementing custom assertions. Personally, I find them invaluable, especially when
working with rich domain objects. As soon as I no longer feel comfortable using the default assertions
(assertEquals(), assertTrue()), I write a custom matcher instead. Usually this solves my problem.
In my experience, it quite often happens that the custom matchers one has written for unit tests get reused
later for integration and/or end-to-end tests. This increases the "return on the investment" one had to
make to implement them.
As a last tip, I would suggest that if you use matchers, you should use them everywhere, so that all your
assertions begin with assertThat(). This will make your tests very readable indeed.
112
any()
anyVararg()
isNull(), isNotNull()
isA(Class<T> clazz)
same(T value)
refEq(T value, String excludeFields) matches an object that is reflection-equal to the given value;
eq(boolean value), eq(byte value), eq(char value), eq(double value), eq(float value), eq(int
value), eq(long value), eq(short value), eq(T value)
arguments.
Many of the above methods also exists with additional arguments (of the java.lang.Class type) to make
them generics-friendly: i.e. to avoid compiler warnings.
12
For the full list of available matchers please refer to the Mockito documentation relating to the Matchers class.
113
startsWith(String prefix), endsWith(String suffix) match a string that starts/ends with the prefix/
contains(String substring)
matches(String regex)
Such matchers are useful for specifying some "generic" stubbing behaviour or expectations. For
example, such code will make the userDAO stub return the object user every time its getUser() method
is called, regardless of what ID parameter is passed there.
argThat(org.hamcrest.Matcher<T> matcher),
booleanThat(Matcher<Boolean>
charThat(Matcher<Character>
floatThat(Matcher<Float>
matcher),
matcher),
matcher),
byteThat(Matcher<Byte>
matcher),
doubleThat(Matcher<Double>
matcher),
intThat(Matcher<Integer>
matcher),
This is because all Hamcrest matcher methods return objects of the org.hamcrest.Matcher<T> type, while Mockito matchers
return objects of the T type.
14
http://jakarta.apache.org/jmeter/
115
The SystemIdGenerator class uses a static method of the System class to obtain unique identifiers.
To test if the returned IDs are really unique, we need to call the nextId() method of our ID generator
two times in a row, and compare the results. Such a test is shown in Listing 6.20.
Even though some time passes between the generation of idA and idB this test fails every time I execute
it. This means that both of the identifiers generated by an instance of the SystemIdGenerator class are
equal. Apparently, current CPUs are fast enough to execute the nextId() method two times in every
116
If we run our test in Listing 6.20 against this version of an ID generator, the test will pass. No matter
how many times we execute the test, no matter if we add a for loop inside the test code to repeat it again
and again, it will pass. Yet, it does not mean that our generator class is ready to be used in the real world.
In the next step we will prove it is still not robust enough.
If you expect your code to be used concurrently, then your tests should simulate this.
Even if a unary increment operator were atomic (which it isnt!), it might happen that two threads both
execute the nextId() method and get the same value. How? Well, two threads might obtain the same
"old" value of the nextId variable, then both might increment it and subsequently assign a "new" value
to the idA and idB variables. To write a test which exposes such a threat, we would have to create two
separate threads and make them access nextId() in exactly this way which is by no means easy.
Fortunately, TestNG offers a nice way to solve this dilemma.
The solution, shown in Listing 6.22, relies on two attributes of the @Test annotation:
threadPoolSize,
which sets the number of threads that are to execute a test method,
invocationCount,
117
The test uses method add() of the HashSet class, which returns true if, and only if, the element
added was not already in the set. In other words, the test will fail if the ID generated is not unique.
The idsShouldBeUnique() method will be invoked 100 times, by 7 threads simultaneously. Please
note that we need not create any Thread objects in the code. Everything has already been done,
thanks to the @Test annotation attributes.
If you run the test against the AtomicIdGenerator class now, you should see it fail. Apparently, our ID
generator is not yet ready to be used by multiple clients at the same time.
6.7.4. Conclusions
Let us leave the implementation of an ID generator as homework for you, dear reader (see Section
6.12.6), and concentrate on the testing side of our example. Here are some comments on what we have
seen so far, and also some remarks about further enhancements to the test we have just written.
First of all, we have learned that TestNG allows us to execute tests methods concurrently, through the
simple use of annotations. There is no need for you to implement threads yourself. Instead, use the
threadPoolSize and invocationCount attributes of @Test annotation. As the examples have shown, this
makes testing code very clean and easy to understand. Definitely a good thing!
In addition to what we have done, you can also use the timeOut and invocationTimeOut attributes of
@Test annotation. Their role is to break the test execution and fail the test if it takes too long (e.g. if your
code has caused a deadlock or entered some infinite loop). These annotations are especially useful for
integration testing (when external modules or applications can cause unacceptable delays). Please refer
to TestNG documentation for detailed information.
The examples presented in this section do not solve the problem of testing and concurrency.
In fact, we have only touched on a part of it. Right now we know how to test our code
simultaneously with many threads. However, if production code creates threads, then testing
it raises other new and complicated issues. [goetz2006] is the book on Java concurrency, and
it contains some hints on the testing of concurrent code. JMock library offers some support
for multithread code testing15. There are also some libraries which can help you with this task.
See http://www.jmock.org/threads.html
118
Returns the current date (at the time of the tests execution).
Please do not be offended by this "HelloWorld" style example. Its point is that it
encapsulates everything problematic about the unit testing of time-dependent code. I have
seen complicated business code with exactly the same issue as is shown in Listing 6.23. If
you learn to solve the problem of Hello class, you will also know how to deal with much
more complicated logic.
Whatever test we write in connection with this simple Hello class, its result will depend on the time
of execution. An example is shown in Listing 6.24. After execution, one of the tests will fail. This is
something we cannot accept. What is expected of unit tests is that they abstract from the environment
and make sure that a given class always works.
See http://en.wikipedia.org/wiki/Time_formatting_and_storage_bugs
119
A default implementation of the TimeProvider interface shown in Listing 6.25 would probably reuse the
system calendar (Calendar.getInstance()).
The TimeProvider collaborator has been injected as a constructor parameter, which means it is
easily replaceable with a test double.
timeProvider.getTime() is used instead of Calendar.getInstance().
Suddenly, the tests of the redesigned
implementation.
Hello
120
Here a mock of TimeProvider has been created and injected into the SUT17.
Because the test-fixture setting code grew, I decided to put it into a separate method. See Section 9.7.2 for some discussion.
121
6.8.2. Conclusions
In this section we have discussed how to deal with time-dependent SUTs. The solution is quite simple:
make time one of the SUTs collaborators, and then do exactly what you would with other collaborators:
replace it with a test double. Once you have done this, your design will be improved (the SUT is freed
from time-management knowledge and can focus on business logic), and you can then proceed with a
standard approach to all collaborators. Yes, this is enough to triumph over time (at least in unit tests). :)
The technique presented in this section is sufficient to deal with the time problem at the unit-testing
level. However, it does not solve many problems related to time that you will encounter when testing
applications on a higher level. The different time-zones of servers and databases, triggers in databases, or
external processes running only during certain hours of the night, as well as security certificates whose
viability expires, will all give you a good deal of trouble. Fortunately, though, none of these affect unit
tests!
122
18
Each of the methods also has an overloaded version which takes a String message as an additional parameter. See http://testng.org/
javadocs/org/testng/Assert.html
123
- returns
true
if two
- returns true if
the same elements exists in both arrays, but does not require them to be in the same order.
assertEqualsNoOrder(java.lang.Object[] actual, java.lang.Object[] expected)
The first three methods - for Map, Set and Collection - return true if both parameters contain the same
elements. No order is considered, even if a particular implementation of the Map, Set or Collection
interface backs up ordering. Listing 6.30 presents an example of such a situation: both sets are considered
equal, even if the order of insertion (which is taken into account by LinkedHashSet) is not the same.
http://www.unitils.org/
http://code.google.com/p/hamcrest/
21
http://fest.codehaus.org/Fluent+Assertions+Module
20
124
Unitils
The test shown in Listing 6.32 gives an example of testing collections content using Unitils. With Unitils,
it is up to the programmer to decide what it means for two collections to be considered "equal". For the
sake of brevity, this test uses the same sets (setA and setB) as shown in Listing 6.30.
125
See http://martinfowler.com/bliki/FluentInterface.html
126
static
static
static
static
static
org.hamcrest.MatcherAssert.assertThat;
org.hamcrest.collection.IsCollectionContaining.hasItem;
org.hamcrest.collection.IsCollectionContaining.hasItems;
org.hamcrest.collection.IsMapContaining.hasEntry;
org.hamcrest.collection.IsMapContaining.hasKey;
A constructor of the Book class sets its two fields - author and title.
These two assertions will pass.
This one will fail - my books collection does not include any work by "Bill Clinton".
Both Hamcrest and FEST offer very detailed and readable error messages. For example, when looking
for the String "xyz" in a set of two Strings comprising "s1" and "s2", the following message is printed
by Hamcrest:
127
6.9.5. Conclusions
In this section various ways of testing collections have been discussed. First, we looked at what TestNG
offers in this respect. Then, examples of Unitils, FEST Fluent Assertions and Hamcrest were given,
along with brief information about other features of these libraries. Finally, we took a look at custom
solutions.
In conclusion, if your tests involve a great deal of collections testing, I would suggest investing time in
mastering one of the libraries presented in this section. FEST Fluent Assertions seems to me the best
choice (when it comes to collection testing), because it provides a lot of useful assertions and is very
extensible, so you can also add your own if required.
23
128
This data provider returns an iterator (see Section 3.6.4) and throws some exceptions, which may
occur when reading and parsing an Excel file.
The principal objects are created using Java Excel API24.
The first row contains column names, so we skip it.
The data is read from the Excel file.
An iterator containing all of the required data is returned.
The test method gets data from the discountData provider.
A normal TestNG assertion ensues, to make sure that DiscountCalculator returns reasonable
results.
6.11. Conclusions
We started this section by discussing a few techniques that should definitely be in your testing toolbox.
In particular, we took a detailed look at expected exceptions testing, and learned what matchers are
good for.
24
See http://jexcelapi.sourceforge.net/.
129
130
6.12. Exercises
In this section we have been discussing a number of aspects of advanced unit testing. Now it is time to
practice some of these freshly acquired skills.
Design the test cases for this method! Please note that this time you will have to think not only about the
input parameters (user), but also about the values returned (or exceptions thrown!) by securityService
and userDAO.
131
132
Make sure you take care of any failed assertion messages in such a way that the cause of a failure is
explicitly given.
Write some tests using your matcher, and decide whether it was worth the trouble of implementing it.
133
http://commons.apache.org/lang/
http://java.net/projects/quickcheck
3
http://databene.org/feed4testng.html
2
134
A test of this class can take advantage of random values. Such an attempt is shown in Listing 7.2.
As far as I understand the idea behind the implementation shown in Listing 7.2, random values are to
be used because they (supposedly) highlight the robustness of a given test. It is as if the test were to
shout "Hey look, every time I execute the test it uses a different users name and still passes! Amazing,
isnt it?".
135
This test method is executed 100 times with different random values.
Even if the test in Listing 7.3 looks much more serious than the previous one, it is not really much
stronger. It only tricks us into thinking that UserToPersonConverter has now been thoroughly tested.
Unfortunately it hasnt been.
Let us take another look at the implementation of the UserToPersonConverter class (shown in Listing
7.1). Has it been tested more effectively, just because we have passed 100 nonsensical, unpronounceable
names (each time of the same length, namely 8 and 12)? I do not think so. The probability that tests 2
to 100 will reveal some bugs not discovered by the first test is minimal. The diversity of test parameters
is very limited, and so is the value added by each of the tests. It would not increase, even if we were to
up the number of randomly generated values from 100 to 1000.
When it comes to testing, I would rather prioritize the quality of test cases over the quantity. A good
quality test case can expose some holes within the production code. I suggest thinking carefully about the
possible scenarios (as discussed in Section 6.1) and then making a deliberate choice of some values. My
test of the UserToPersonConverter class would definitely contain cases of names and surnames of varied
length (including empty strings), with varied capitalization. I might even use some randomness to avoid
putting so many names directly in the test code; however, I would make sure that some borderline cases
(e.g. empty or extremely long strings) are verified. The variety of my test parameters would definitely
be far greater than that generated by the data provider in Listing 7.3.
7.1.3. Conclusions
As you will have observed for yourself, generating multiple tests with random values does not
automatically make the test suite stronger. Instead, it can complicate your tests and give rise to a number
of issues. However, if randomness is really appropriate within the context of your testing domain, then
at least try to do it right. Table 7.1 offers some hints and discusses issues relating to the use of random
values in your tests.
136
comment
Every time the test fails, add the values which made it fail to
your test. And of course, make it pass with these values.
If you are interested in details, please refer to Jaroslav Tulachs article at http://wiki.apidesign.org/wiki/RandomizedTest
Some specialized tools, e.g. Quickcheck, provide solutions for some of the issues described
above.
I have to admit I am not a big fan of using random values in tests. I do not see many cases where using
them would improve the test. In general, I would rather suggest:
spending more time pondering over important values which should be verified (see the discussion in
Section 6.1) instead of generating thousands of random cases.
using meaningful names instead of random garbage strings.
137
138
void testDeletion() {
adds user Y to the system
verify that it exists (so later we know that it was actually removed)
removes user Y
makes sure it does not exist, by issuing SQL query against the database
See http://sourcemaking.com/refactoring/extract-method
139
Here we have a case of explicit dependency involving the dependsOnMethods attribute of the @Test
annotation.
This time, an explicit dependency is established between the tests. It brings with it the following
properties:
It is guaranteed that testDeletion() will be executed after testAddition().
If testAddition() fails then testDeletion() will be skipped. This seems right: why bother with testing
of "delete" if "add" does not work?
The DRY principle is honoured. There is no repetition of code at all. No need to refactor in order to
extract any helper methods.
The dependency of both tests is expressed explicitly (with the dependsOnMethods attribute of the @Test
annotation). The testDeletion() test expects certain data stored in a database by testAddition() to
be there.
To understand testDeletion() one must also understand what
browsing through the code base, which is an additional effort.
testAddition()
See http://en.wikipedia.org/wiki/Fail-fast
140
Of course, after you have fixed the constructor, you might find out that other methods of the SUT are also flawed. But you will be
able to discover the problems one at a time, which makes them far easier to fix.
141
The SUT is initiated only once and is not cleaned before each test.
This test changes the state of the SUT.
142
someObject
is
Surprisingly, the tests on Listing 7.8 might work pretty well! As long as the testing framework selects a
"proper" (e.g. alphabetical) order of executing them, they will pass. However, if even the slightest change
is introduced, they might fail at some point. This can be induced by a change in the tests (e.g. addition
of a new test method, or some innocent-seeming refactoring), but also by a change of environment (e.g.
an upgrading of your JDK). Fixing this bug might not be an easy task, and will surely be preceded with
head-scratching and repeating things like "it has to work, it always did!". Neither will help, as the tests
passed thousands of times accidentally. Now they do not, and you need to investigate the case.
If you have dependencies in your tests, then better name them explicitly.
The SUT an object of the Account class - is created only once for all tests of this class (as dictated
by the @BeforeClass annotation). Any changes introduced into it by a test method will be visible
to any subsequently executed test method.
143
Now, if we execute our test class with this new test method, two things can happen, depending on the
order of execution (which is not guaranteed by default):
If we are lucky, the new test method gets executed at the very end of the test suite, and nothing bad
will happen.
If
the
new
test
method
shouldAllowToDepositMoney()
and
A careful programmer will spot this danger at once and take precautionary measures. In particular,
adding another test dependency will guarantee that the methods are executed in the desired order. The
resulting test might take the form shown in Listing 7.11.
A new test dependency is introduced to make sure that we do not zero the accounts balance before
attempting to withdraw from it.
Okay, we have managed to do it this time, but is what we have done right? Does the test for the account
close() method have anything to do with the test for withdraw() ? Is this dependency semantically
correct? I feel as if we had just been guilty of a misuse of test dependencies.
144
145
The creation of the account object is guaranteed to happen before each test method.
The state of the account object is known, and we can verify the results of methods that have been
executed by performing comparisons with this initial state.
New test methods are added "just like that" - no additional effort is required.
This simple change having the SUT created before each method ensures that its state will be well
known to each of them. This simplifies things greatly and renders test dependencies obsolete. Adding
a new test method will now be completely painless.
As this example demonstrates, sometimes our design decisions (i.e. the way we go about the process
of test fixture creation) force us to use test dependencies. With unit tests we have a lot of freedom to
decide about how the SUT is to be created. My advice is to take full advantage of this and aim at having
independent tests, which are much simpler to understand and cheaper to maintain.
7.2.5. Conclusions
The examples presented in this section demonstrate that test dependencies can take various forms. If
we use them, there is always some trade-off involved. We can opt for test independence, or we can
concentrate on the DRY principle and the fail fast approach. Once again, there is no easy answer as
to which way to go. It depends on which of these test code features you value more.
I have witnessed (and have even participated in creating) some test code which was completely
impossible to maintain, owing to the number of dependencies between test methods. These dependencies
made any changes to the test code virtually impossible, at the same time as adding very little in return.
What made it even harder was that some dependencies were not expressed explicitly.
146
See http://www.artima.com/weblogs/viewpost.jsp?thread=35578
147
anAddress.getAddr1());
anAddress.getCsp());
anAddress.getCountry());
As you can see, OAPTM in us having a lot of very focused, tiny, often even just one-line, test methods.
To get a broader understanding of "what address parsing looks like", you need to scan at least a few of
them. What you get in return is that if a constructor of the Address class does not work properly, you
will know all about it - i.e. failing test cases will tell you exactly what works and what doesnt.
A counterpart test i.e. a test which uses several assertions per test method is shown in Listing 7.14.
For
IL
One important thing to notice is that even though in the second version of the test there is more than
one assert per test method, each test method tests only one thing - the ability of the Address constructor
to parse addresses properly.
Table 7.2. Arguments for using only one assert per test
argument
comment
If you write good test with many asserts you can achieve the
same effect. Current IDEs are capable of telling you exactly
which assertion failed, so I do not see any gain from using
OAPTM in this aspect.
It is easier to create intention-revealing Maybe so, but as proved by original code on Listing
method names for one-assertion tests. 7.13, it is still pretty easy to come with lousy names (e.g.
testCsp()) even if using one assert per test! I am confident
that finding good intention-revealing names for many149
comment
assertions is possible, and that OATPM does not have any
advantages here.
7.3.3. Conclusions
Even as a firm believer in small, focused, easy-to-understand methods, I think that OAPTM goes too far,
and does more harm than good. It results in too many lines of code being scattered amongst a multitude
of tiny methods something which is much harder to understand and maintain. It saves me from one
problem (having too many assertions per test method), only to inflict on me another (having too many
test methods). No. Sorry, OAPTM! I can judge on my own when a test method is getting too large,
without needing to follow such dogmatic rules. And as long as I stick to the TDD approach, I will rarely,
if ever, be stricken by the downside of the multiple asserts approach. My test methods are very concise
and readable, and I can easily find intention-revealing names for them. My IDE will guide me straight
to the fallen assertion every time a test fails.
My advice would be not to take the "one assert per test" recommendation too literally. Get clear about the
reasons behind it, but follow another, similar rule, which says that each test method should concentrate
on a single feature of the SUT. Sometimes numerous assertions will be required to test a certain feature,
sometimes one will suffice. But in my opinion, the number of assertions should not be your main concern.
What really matters is the scope of the SUT features covered by each test method.
The only thing that would get me writing so many tiny test methods would be if I was being
paid by LOCs. :)
As extreme programmers put it, "you should listen to your code" and follow its advices.
150
http://en.wikipedia.org/wiki/Deja_vu
151
Reflection
This technique uses a Method class from the java.lang.reflect package11, which allows one to gather
information on methods, but also to tweak them e.g. introducing changes to their access modifiers. An
application of this class in test code is shown in Listing 7.16.
See http://docs.oracle.com/javase/7/docs/api/java/lang/reflect/package-summary.html
152
All reflection calls are hidden behind a convenient API. You do not even have to cast the result
to an appropriate type.
Even though this code looks much nicer than that of the previous attempt, it still cannot be refactored
safely. Calling methods using their name (String) as the parameter is not a healthy approach.
One more thing to note is that neither the approach involving direct use of reflection, nor that which
makes use of Powermock, require us to modify the production code. This is a good thing.
Access Modifiers
Another option we have is to weaken the access modifier of a private method something which will
make it more easily accessible by test code. However, we do not usually want to make such a method
public. Adding new methods to the API of a class, just because we want to test it, would be too much.
Fortunately, we can achieve our goal by relaxing the access modifier just a little. This is shown in Listing
7.18.
7.4.4. Conclusions
When writing the section on private methods testing, I must confess I was in two minds as to whether I
should describe this at all. One part of me argued that it is evil and anti-OO, and that I should not include
it in a book that sets out to promote good practice, and that puts a lot of pressure on one with respect
to the quality of ones code. The other part of me argued that I should have faith in my readers. My
role will be to present and describe the different options so that you, dear reader, can decide by yourself
which way to go. So it looks as though, in the end, this second part of me must have prevailed!
I have tried very hard to discourage you from testing private methods. I still think that with good design,
you will never need to test them directly. However, I do think that sometimes (very rarely, but still)
you might need to use the techniques described in this section. This is why I have decided to include
them in the book.
A note on tools. The authors of some tools - e.g. TestNG or JUnit - have never got around to
enhancing their tools in order to make them capable of testing private methods - even though
there have been some expectations on the part of community members that they would do
so. This is probably because they view private methods testing as something that does not
deserve to be facilitated.
Listing 7.19. Typical use of the Java new operator within the method body
public class MySut {
public void myMethod() {
MyCollaborator collaborator = new MyCollaborator();
// some behaviour worth testing here which uses collaborator
}
}
154
org.powermock.api.mockito.PowerMockito;
org.powermock.core.classloader.annotations.PrepareForTest;
org.testng.IObjectFactory;
org.testng.annotations.ObjectFactory;
@PrepareForTest(MySut.class)
public class MySutTest {
@ObjectFactory
public IObjectFactory getObjectFactory() {
return new org.powermock.modules.testng.PowerMockObjectFactory();
}
@Test
public void testMyMethod() throws Exception {
MySut sut = new MySut();
MyCollaborator collaborator = mock(MyCollaborator.class);
PowerMockito.whenNew(MyCollaborator.class)
.withNoArguments().thenReturn(collaborator);
// normal test using Mockito's syntax
// e.g. Mockito.when(collaborator.someMethod()).thenReturn(...)
}
}
In this case, the @PrepareForTest annotation informs PowerMock that the MySut class will create a
new instance of some other class. In general, this is how PowerMock learns, about which classes
it should perform some bytecode manipulation.
In order to use PowerMock with TestNG, we need to make PowerMock responsible for the creation
of all of the test instances.
The test double is created as usual - with the static mock() method of Mockito.
This is where the magic happens: whenever a new object of the MyCollaborator class gets created,
our test double object (collaborator) will be used instead. Two of PowerMocks methods whenNew() and withNoArguments() - are used to control the execution of a no-arguments constructor
of the MyCollaborator class.
There is nothing special in the test method itself - we can use normal Mockito syntax to verify the
behaviour, to stub or to spy.
156
MyCollaborator
An object of the MyCollaborator class is provided by MySut's clients when they create objects of
the MySut class.
No new operator is used within myMethod(). The collaborator object has been created outside of
the MySut class and passed as a constructor parameter.
The myMethod() method does not deal with the creation of collaborators anymore. It uses a collab object
of the MyCollaborator class, which is already available when myMethod() is executed.
The updated constructor of the MySut class allows for straightforward injection of a collaborator
test double.
The test in Listing 7.23 holds no surprises for us. Replacing the collaborator of sut is simply a matter
of passing the appropriate test double to its constructor.
As this example demonstrates, a complicated case can be turned into something far simpler (from a
testing point of view) by the redesign of the SUT. If it is possible to replace the cumbersome creation of
objects (involving either the new operator or static factory methods) with a dependency injection, then
testing becomes a trivial task.
Even so, there are some downsides or, at least, some issues we should be aware of:
production code gets altered to meet the requirements of the tests themselves (isnt this a case of the
tail wagging the dog?),
such a redesign breaks existing clients (it truly is a redesign, not a refactoring),
you need to write some additional code.
158
Instead of invoking the new operator directly there is a call to a new method.
I strongly recommend adding a short comment to the extracted method, so it is clear that it has
been created for the purpose of conducting unit tests.
The extracted method has a default access modifier, and not very impressive content.
As for the access modifier of the extracted createCollaborator() method, we can choose between
making it protected or using default access protection (so-called "package-private"). This has some
impact on our test classes. If we keep them in the same package as the production code, then the default
access will be good enough. If they reside in different packages, then we will need to make the access less
restrictive (protected). Some information on the organization of test packages is given in Section 9.1.
The change introduced to the original class is minimal. All we did is a simple "extract method"
refactoring. At first it might seem useless, but in fact it opens up a new testing possibility. Listing 7.25
shows a test which takes advantage of this minor refactoring.
159
A new class is introduced - a subclass of the original class (the one we intend to test). An object
of this newly introduced class - MyRefactoredSutSubclassed - will be tested.
The new class overrides the createCollaborator() method. The new implementation returns a test
double of the MyCollaborator class.
There is no need to inject collaborator to sut - this is done by a myMethod() of SUTs parent class
(see Listing 7.24).
This simple technique, as presented in this section, can be really handy. Let us conclude by now listing
some of its pros and cons:
It does not break the clients (the SUTs API has not been changed) and it lets you write tests at the
same time.
Changes are limited to the SUT class.
The design of production code is somewhat worse than it was before the refactoring. The newly
introduced method is awkward, and poses a potential encapsulation issue. (I must remark that I have
never seen any harm being done because of this slight reduction in the SUTs integrity.)
The SUTs myMethod() still creates collaborators (instead of focusing on its business tasks), which
means its design has not been improved.
Some people feel bad about testing a subclass instead of a real SUT. Personally, I would be very
happy to test the real thing, but just having a test of a strictly controlled subclass has proved more
than adequate for my purposes.
Extracted method.
So far, nothing new here. The difference is only visible when it comes to the tests class. But before we
inspect any new code, we need to learn something new about Mockito. Mockito allows us to "spy" on
real objects. That means we can decide which methods of a real object are invoked, and which are being
intercepted (and stubbed). The Javadoc of the spy() method explains this in the following way: "Creates
a spy of the real object. The spy calls real methods unless they are stubbed."
This feature is deployed in Listing 7.27, which illustrates the use of a partial mocking technique.
Additionally, it presents a new static Mockito method - doReturn(). We use
doReturn(collaborator).when(sut).createCollaborator();
instead of
when(collaborator.someMethod()).thenReturn(true);
Surprise! The SUT has not been created using the new operator. Instead, another static method of
Mockito has been used.
Another unusual situation. We request that our SUT returns some canned values for a given method
invocation.
As was mentioned before, when created with the spy() method sut behaves like a normal object of its
class, until some of its methods are stubbed. In the case of our example, all the SUTs methods, except for
createCollaborator(), would be executed as if sut had been created with the new keyword. However,
161
7.5.5. Conclusions
In this section, we have discussed various options for testing code which uses the new operator to create
collaborators. Four different approaches have been discussed. Each of them had some pros and cons,
which have been discussed in the sections above. Table 7.3 summarizes the salient features of each of
the options on offer.
redesign
refactor &
subclass
partial mocking
required SUT
change
no change
API change,
DI introduced
(breaking clients)
SUTs design
no change
162
redesign
collaborators
creation
refactor &
subclass
extracted to
facilitate testing)
partial mocking
extracted to
facilitate testing)
test code
complicated,
complicated, SUT
testing subclass of is tested and also
SUT
stubbed
amount of work
minimal
might be
significant
medium
SUT is a final
class
not a problem
not a problem
The PowerMock option is especially attractive when working with legacy code, which is something
we cannot modify (or are too scared to modify). Its selling point is its ability to test nasty code
without any struggle.
Redesign is probably the right way to go, but it requires more work than other techniques, and breaks
clients (because of API change). Its main benefit is improved design of production code.
Both Refactor & Subclass and Partial Mocking offer similar benefits: the ability to test classes
without API change. However, they require some effort, cannot be used with final classes, and do
not make production code better (they rather make it slightly worse).
To conclude, I would strongly recommend that you always aim at making the design better, thus leaving
PowerMock as a tool of "last resort" one that may save your life when battling with especially vicious
legacy code.
PIM
Calendar
Meeting
- a collaborator of PIM.
http://en.wikipedia.org/wiki/Personal_information_manager
163
The collaborator is passed as a constructor argument - there will be no problem with injecting its
test double into the SUT within the test code.
A new object of the Meeting type is created, and is then used as a parameter to the collaborators
addEvent() method.
The problem we face when testing the PIM class is the following: how to make sure that the addMeeting()
method constructs a proper Meeting object? We need to somehow intercept the parameter passed to
calendar.addEvent(). There are two ways we can do it.
The problem with addMeeting() method testing comes from its poor design. It is responsible
for too many things - it deals with the creation of the Meeting object, and interacts with the
calendar collaborator. If we were to split its functionality and, for example, introduce another
collaborator responsible for the creation of proper Meeting objects, than there would be no
issue with testing arguments of the addEvent() method!
164
An object of the Meeting class is created, identical to the one which we expect to be created by
SUTs addMeeting() method.
Execution of the method of the SUT being tested.
Verification of whether the calendar.addEvent() method has been called with exactly the same
Meeting object.
Looks good? Yes, but unfortunately it does not work. The test fails with the following failure message
(stacktrace lines have been omitted for greater readability):
Hmm, strange! I could have sworn that the addMeeting() method constructs a proper Meeting object
And in fact it does! The problem lies elsewhere. The Meeting class does not override the equals()
method, so the objects equality is verified by reference, and thus fails. We can fix it by adding
appropriate methods13 to the Meeting class. Below you can see an implementation of the equals()
method generated by IntelliJ IDEA:
13
165
The hashCode() method implementation is not important right now, but remember: it should also
be overridden!
Now, if we rerun the test, it passes. Good, we have the first solution to the problem of verifying whether
the arguments passed to the collaborator are as expected.
However, this is not an ideal solution. On the plus side, we may say that:
it works!
it is quite straightforward and easy to understand.
Unfortunately, there are more things to say on the minus side:
A domain object in question might not have the equals() method implemented.
In worse cases, a domain objects equals() might already be implemented, and might behave
differently than as required by our test.
The verification is "total" - it checks everything that our
to overspecified tests.
equals()
166
An object of the ArgumentCaptor class is created, which will gather information on arguments of
the type Meeting.
The addEvent() methods having been called is verified, and Mockito is instructed to capture
arguments of this method call.
The actual argument to the addEvent() method is extracted from the ArgumentCaptor object.
What we have here are classic assertions which verify that the right object has been passed as an
argument to the addEvent() method.
As shown in Listing 7.34, we can use ArgumentCaptor to verify arguments passed to collaborators. This
solution has some positive features:
it does not rely on the equals() method of the domain object (in our case, of the Meeting class),
it can be used to test arbitrary properties of arguments,
"normal" assertions are used to specify our expectations regarding the arguments.
In general, Mockito does a good job of facilitating the task of verifying a collaborators arguments.
However, as the Mockito documentation warns, having to use ArgumentCaptor might be indicative that
the code is not well-designed:
Over reliance on capturing arguments would be a code smell in my opinion as most
well abstracted code should not need to do this. However for testing legacy code and
interactions with outside systems ArgumentCaptors can be very useful.
Mockito Documentation
7.7. Conclusions
The issues discussed in this chapter are nothing short of real-life problems. You will encounter them
mostly when working with legacy code, but also when making decisions about how to design the
167
168
7.8. Exercises
Let us recap what we have learned in this chapter by doing some exercises.
Please note that static methods can be tested with the same approaches as the new operator, which was
discussed in Section 7.5.
169
171
The green bar on top makes it clear there are no failed tests. The pane on the left provides the list of
executed tests (in the form of a tree, so you can see which class and package they belong to). Information
on execution time is also provided, even though this is usually not so important with unit tests. As Figure
8.1 shows, in cases of tests which use data providers, detailed information on arguments is printed as
well. Moreover, there is a console pane, which shows the output of each test and any other messages
printed by the testing framework. (Even so, there are not many occasions when we would have a reason
to want to check its content, if all of the tests have passed).
In the event of failure, Eclipse will warn you about the problem by changing the bar color from green
to red. As Figure 8.2 shows, Eclipse also provides the following information:
which test method failed and, in the case of data providers, what the arguments were (in our case
-7 and BLA),
a failure exception message which is "clickable", so you can easily move to the test code and start
fixing things.
Eclipse also makes it possible to rerun all recently executed tests, or to run only the failed ones (these
two options are marked with red rectangles in the picture above).
172
If you want to know more you need to customize the view. IntelliJ IDEA will use the latest settings of
the Test Runner Tab, so configuring it will be a one-off action. In order to see what tests have been run,
switch off the Hide Passed button and select the Expand All button. In addition, to get the test execution
statistics (i.e. execution time) select the Show Statistics option from the cog button menu. The resulting
view is shown in Figure 8.4 (red rectangles mark the aforementioned options).
You can adjust the size of each pane to your liking (when preparing illustrations for this book, I was
obliged to shrink this slightly, so unfortunately some parts may not be fully visible).
This time much more information is available. The left pane lists all the test methods executed during
the last run in the form of a tree (with each package and class as a node, and each test method as a tree
leaf). The pane in the middle shows the console output of each of the tests (in this case the tests have
not printed any messages, so it is almost empty). Clicking on test names (in the left panel) results in the
middle pane showing the test output for a selected test case.
173
It is possible to configure the Test Runner Tab so that after having executed the tests it focuses on the
first failed test. Figure 8.5 shows such a scenario. The assertion error is printed along with the precise
lines of test code where the verification failed. They are clickable, so you can easily move to the test
code and start fixing things.
8.1.3. Conclusion
As we have observed in the course this section, both IntelliJ IDEA and Eclipse provide highly readable
test execution reports. The overall result is clearly visible in the form of a green or red bar. The results
of each test are also shown. In cases of passed tests, only a minimal amount of information is printed,
so the screen does not become clogged up with unimportant data. However, in the event of failure, both
IDEs show more of the data, and this helps you to fix the bug right away. They offer quick navigation
from assertion error to test code.
Gradle suite
|-- Gradle test.html
|-- Gradle test.properties
|-- Gradle test.xml
|-- classes.html
|-- groups.html
|-- index.html
|-- main.html
|-- methods-alphabetical.html
|-- methods-not-run.html
|-- methods.html
|-- reporter-output.html
|-- testng-failed.xml
|-- testng.xml.html
`-- toc.html
emailable-report.html
index.html
testng-failed.xml
testng-results.xml
testng.css
A set of comprehensive reports on tests that have been run. Check it, if you want detailed
information, or when you are looking for some bug or weird behaviour of your tests. You will find
a lot of data here: information on groups, classes, test methods which have not been executed, etc.
A concise HTML report, well-suited to being sent by email to the team (or anyone interested in
the results of the tests).
A summary of the execution of the tests, in HTML format. Not really helpful, but it does link to
the full report.
An XML file with the names of any failed tests. Not useful for debugging, as it contains only the
names of the tests - no stacktrace or error messages of failed assertions are available here. But its
purpose is to help with the rerunning of failed tests.
Comprehensive information on all tests that have been run (in XML format).
When working with command line I would suggest you check the testng-results.xml file and look for
a FAIL message within the file. You can also create some bash aliases or scripts to retrieve interesting
information from these files with a single command. In the event that you need a more sectional view,
I suggest using the HTML reports.
Now, if you visit the HTML report, you will find this message printed. It is visible next to the test results
(as shown in Figure 8.6) and also on a separate report page, which groups all output logged with the
Reporter.log() method. You can even put some HTML tags into your log message.
Logs of the Reporter class can be adjusted using log levels (see TestNG Javadocs).
Writing your own reporter is not very complicated, but does require some knowledge of the internal data
structures of TestNG. Fortunately, the existence of numerous sample reporters (see the TestNG source
code, org.testng.reporters package) will furnish you with a lot of examples to learn from.
In order to develop such a report, you should implement an
method: generateReport(). Then you must do the following:
IReporter
generateReport()
method of the
See http://poi.apache.org/.
177
The
Iterating through the results of each test suite. Objects of the ISuiteResult type hold information
on test methods that have failed, passed or been skipped. There are also separate objects which
track the skipped and failed configuration methods - for example, methods annotated with the
@BeforeClass annotation). Each time the writeTestMethodResult() method is invoked, where this
actually writes the final data to the cells of the Excel spreadsheet (see the next listing).
178
The writeTestMethodResults() method iterates through method results (of the ITestResult type)
and creates Excel cells with the test class name, test method name, and the execution result (as
shown in Figure 8.7).
The details of the creation of the spreadsheet cells (enclosed within the createCell() method) are
specific to Apache POI, and have been omitted for the sake of brevity - you will find them in the
books source code.
The example presented in this section proves that TestNG offers enough information to create a
detailed report of the test execution. The output format can be whatever is required: pure text, an Excel
spreadsheet or some graphic representation of passed and failed tests (e.g. a bar chart).
Appendix B, Running Unit Tests explains how to make TestNG use your custom reporter.
description
onStart(ITestContext context)
description
onFinish(ITestContext context)
onTestStart(ITestResult result)
onTestFailure(ITestResult result)
onTestSkipped(ITestResult result)
onTestSuccess(ITestResult result)
onTestFailedButWithinSuccessPercentage
(ITestResult result)
As shown in Table 8.1, you can get information regarding all of the tests that have been executed
(analyzing objects of the ITestContext type that have been passed to the onFinish() method), or inspect
the results of each single test by analyzing objects of the ITestResult type that have been passed to
methods which are invoked before and after the execution of each test. This way you can immediately
print information on progress (e.g. the result of the last test to be executed, its execution time, etc.), but
also provide some summary information (e.g. the number of passed and failed tests).
When writing a custom listener, we could implement the ITestListener interface or extend a
TestListenerAdapter class. The second option is preferable, because this class provides a default
(empty) implementation of all methods of the ITestListener interface, so we only need to override the
ones specifically required for our particular use case.
DotTestListener
The first listener - DotTestListener - is copied directly from the TestNG documentation. It prints a
character for each executed test: . (a dot) for passed test, F for failed, and S for skipped. Its usage brings
two benefits:
it lets you watch the progress of the test (which is quite important if you switched off all test logs,
as advised in Section 8.5),
it makes it very clear whether some tests have failed or been skipped (the letters F and S stand out
clearly from amidst the lines of dots).
Sample output with some failed and skipped tests is shown in Listing 8.6.
180
The implementation, which uses TestListenerAdapter as a parent class, is trivial. It is shown in Listing
8.7.
181
SkippedTestListener
By default, TestNG does not print detailed information on skipped tests. It only prints out the number
of such tests. Because this information is not very easily visible, it has led to my team experiencing
some difficulties. There have been several occasions when we missed information on skipped tests and
proceeded with a false sense of "everything being just fine".
Tests are skipped sometimes for some trivial reasons such as having DataProvider return a different
number of arguments than was expected by the test method. I have noticed that people (me included)
tend to only look at the number of failed tests. Somehow, the information that some were skipped gets
ignored.
The SkippedTestListener listener prints information about skipped tests in the same way that TestNG
informs about failed tests. This way it is hard to overlook them. A sample result is shown in Listing 8.8.
someTestMethod
otherTestMethod
Tests run: 112, Failures: 0, Errors: 0, Skipped: 2, Time elapsed: 0.236 sec
The implementation is very concise thanks to TestAdapterListener, which does the whole job gathering
information on the execution of tests. This is shown in Listing 8.9.
Appendix B, Running Unit Tests explains how to make TestNG use your custom listener.
182
assertXYZ()
10, "wrong
While the first version (without any message) leaves us in doubt about the nature of the problem, the
second version states explicitly that the problem was with money2. The gain is rather minimal: usually
2
183
Hmm, not really much help, is it? In order to improve the message it is enough to override the toString()
method of the Client class, e.g. like this:
failure message
assertTrue(2 * 2 == 5)
java.lang.AssertionError:
Expected :true
Actual
:false
assertEquals(2 * 2, 5)
java.lang.AssertionError:
Expected :5
Actual
:4
assertThat(2 * 2).isEqualTo(5)
184
8.8. Conclusions
In this section we have concentrated on ways of getting feedback information about the execution of
tests. First, we covered feedback generated by the IDE. Then we moved to the output generated by
TestNG. We learned about the default for this, and explored options for customization. We also did
some coding and created our own listeners and reporters. In so doing we made TestNG print information
that was of value to us, both during the execution of the tests and after they had finished. As the
few straightforward examples given here demonstrate, TestNG will furnish us with comprehensive
information about the tests that have been executed, and it is up to us how we use it.
To gather even more data on the execution of tests, we also plunged into the world of assertion messages,
logging and debugging.
3
See http://www.oracle.com/technetwork/java/javamail/index.html
See http://jenkins-ci.org
5
See https://wiki.jenkins-ci.org/display/JENKINS/Plugins
4
186
187
8.9. Exercises
The exercises presented in this section should make you familiar with the default output of tests. They
should also give you some practical experience with the customization of elements responsible for the
content and format of various test execution reports.
FirstTest
FirstTest
FirstTest
FirstTest
FirstTest
SecondTest
SecondTest
SecondTest
SecondTest
SecondTest
fifthTestMethod
firstTestMethod
fourthTestMethod
secondTestMethod
thirdTestMethod
methodA
methodB
methodC
methodD
methodE
1944
3799
1920
4891
2963
3525
1390
117
4571
4552
189
tests,
e.g.
One that I am aware of, derived from the BDD approach, makes the test class name part of a "when" element of a BDD convention
- see http://www.slideshare.net/wakaleo/junit-kung-fu-getting-more-out-of-your-unit-tests
192
MyClassTest
- all tests that puts the "valid" behaviour of the class through its paces. This test class
shows the right way to use MyClass.
2.
MyClassWrongValuesTest - all tests that put the SUT through its paces and fail (fast!) with an expected
exception. This test class shows what happens when MyClass is used in an incorrect way.
The second test class - MyClassWrongValuesTest - is usually much simpler (but sometimes longer) than
MyClassTest. Often it will contain some data providers, whose role is to provide various illegal values
for different test methods. Test doubles are rarely required there (except, maybe, for dummies); this is
because no methods are really called on them, as arguments checking is usually the first thing you do.
The necessity of splitting up a test class might by indicative that what you should really be
splitting up is the class being tested itself! If it cannot be tested with one test class, maybe
it is too big - maybe it has too much responsibility? If so, then fix this problem, and the test
class will automatically shrink to an appropriate length.
Historically, method names were prefixed with the word test - e.g. testConstructor(),
testReturnsNonNullArray(), etc. This naming schema was popularized (or rather enforced) by JUnit,
which treated all methods that followed this pattern as test methods, and executed them during tests
execution (ignoring any methods with different names). And for a long time everyone was happy with it.
However, the limitations of this naming schema started to show up. First of all, it was not obvious
what a particular test method was all about, just by looking at its name. It was quite common to find
lengthy test methods which, under a common name such as, for example, testUserAdd(), verified many
features of a class being tested. This was especially painful when dealing with failed tests, as there
was not much one could learn from the information that "testUserAdd() has failed". Such an error
message does not inform us about exactly what has failed: i.e. which feature of the class tested is not
working properly. Because of this, method names started to grow and contain much more information.
For example testConstructor() was split into several more focused test methods with names like
testConstructorThrowsExceptionForInvalidArguments(), for example.
This was definitely a step in the right direction, but still not quite good enough. Developers at this time
were fascinated by the expressiveness of new dynamic languages (e.g. Ruby2) and fluent interfaces3, and
this meant they were really irritated by the presence of this obligatory test prefix. Many of us demanded
that failed test messages should be readable as proper English sentences (or, at least, be as close to this
ideal as possible). The rescue came with a new wave of testing frameworks (TestNG in particular) which
used annotations instead of method names patterns to recognize test methods. This made it possible to
come up with a more readable naming pattern.
This new pattern was based on the idea that the test method name should convey information about
the following:
preconditions of the test - the state of the SUT and the environment before the test,
triggering actions - what makes the SUT act in the expected way,
expected results of the test - what should be returned by the SUT, or what state the SUT should be in
after the test is finished, or what actions should be performed by the SUT during the test,
optionally, the name or role of the SUT,
in addition, the test prefix was replaced with should, which allows one to create specification-like
method names.
Of course, it is usually not possible to include a full description of all these kinds of information in
the method name itself. What is possible, though, is to include just enough details to convey the main
purpose of the test. Also, each of the elements can be omitted, if its presence does not enhance the
2
http://ruby-lang.org
http://en.wikipedia.org/wiki/Fluent_interface
194
test methods
constructorShouldThrowExceptionForNullUser()
OrderTest
constructorShouldCreateValidOrderForValidUser()
shouldNotAcceptDictionaryBasedPasswords()
shouldNotAcceptPasswordWithoutDigits()
PasswordValidatorTest
shouldNotAcceptShortPasswords()
shouldAcceptLongComplicatedPassword()
shouldAllowToBookTableForOneHourAndMore()
shouldDisallowToBookForLessThanHour()
BookingSystem
shouldAllowToCreateRecurrentReservation()
shouldAllowToCancelExistingReservation()
In the case of the examples presented in Table 9.1, all test method names specify exactly what is expected
of the SUT (e.g. shouldThrow(), shouldNotAccept(), shouldAllow()), and under what conditions
or with what arguments (e.g. ForNullUser(), PasswordsWithoutDigits(), ExistingReservation()).
When a test fails, the first line of the message already furnishes us with enough information to understand
what it is that is not working properly.
What is attractive about this naming schema is that it leaves some room for customization. Some of the
examples shown in Table 9.1 do not start with should, but with the constructor prefix, which makes it
clearer which part of the SUT is being tested by a particular method.
Test method names are of secondary importance compared to their content, but they can
push your thinking in the right direction - or, for that matter, the wrong one. The use of the
"should" prefix helps (some people would say forces) us to focus on the expected behaviour
of the SUT, and leads to "testing behaviour and not methods" (see Section 10.1). Thinking
in terms of the responsibilities of the SUT will make you test at the right level of abstraction.
This is especially important when coding code-first, because it is then so very easy to test
implementation details instead of the behaviour of an external SUT.
The names of variables, as shown in Listing 9.2, inform us about the types of objects (e.g. it is obvious
that mailServer is of the MailServer type). However, they do not convey any information concerning
195
This version of the names of the variables gives much more insight into their purpose in test class. A
single glance is sufficient to let us know that the real testing is to be done using sut and spyMailServer,
while stubTemplateEngineReq is only assisting in this process.
Another variation of this idea is to reverse the order and put the type of test double as a suffix, e.g.
mailServerSpy, templateEngineStub. This way the information concerning the type of the object is more
easily visible something which some people consider more valuable.
It is up to you to decide whether you find this worthwile. With short tests, with a very limited number
of DOCs (as they should be), these additional hints, embedded within the variable names, are rather
unnecessary. If you have more DOCs and more complex tests than it may help you to understand the
tests. On the other hand, short, simple, focused tests are what we should be striving for, so instead of
renaming variables, maybe it would be better just to write better tests.
Whatever naming scheme you decide to follow, please make sure you feel comfortable with
it (and that so do your colleagues).
197
Some people suggest that adding empty lines instead of given/when/then words is good enough. I agree.
198
account.getBalance())
assertEquals(balance,
When it comes to unit tests, there is no such thing as an instance of "pure" BDD. Listing
9.4 shows one possible way to write this test BDD-style, but this is probably not the only
valid way to do it.
As Listing 9.4 shows, in BDD the structure of the test method is really important. Some test methods are
(slightly) longer than necessary, just to satisfy the clear separation between the when and given phases
(e.g. there is no need for a balance variable to exist - assertEquals(account.getBalance(), 60) would
suffice). This approach brings a lot of clarity, and a little bit of redundancy, to every test method.
Another thing to notice is the single assertion within each test method. This is something I criticized in
Section 7.3; however, it starts to make sense with the BDD approach.
Listing 9.6 shows two simple classes which will be used to demonstrate these new Mockito features.
Their names - SUT and Collaborator - reveal their purpose clearly, in both cases.
200
This is where the repetitive code occurs the creation of the SUT, the creation of test doubles,
injecting them and stubbing.
The question is whether we can do anything about this.
Please bear in mind that under "normal" circumstances, the boilerplate code section is much
larger than shown in Listing 9.7. Usually there will be more than one test double in your
code. Multiply it by the number of tests which use test doubles and the reason for cutting
down the size of all of the set up activities becomes evident.
In this line, a test double gets created and stubbed. Note the getMock() method at the end of the
invocation chain.
No test double creation in setUp() method.
201
202
tells Mockito to well, to inject mocks into this particular object. Please note that
the SUT is created here and not in setUp() method.
In contrast to the previous version of the setUp() method, here there is no SUT creation and no
setting of collaborator.
@InjectMocks
Wow! No setting of collaborator, and still the execution of the useCollaborator() method does not fail
with a NullPointerException! In reality the collaborator is injected to sut behind the scenes. Mockito
does this by matching available test doubles with the SUTs fields.
You will be even more surprised when you remove the setter (the setCollaborator() method)
from the SUT class, and watch the test still work. This is because Mockito does not really
execute setters to set fields, but uses a reflection mechanism to modify them directly.
Now, let us summarize and discuss what we have just been learning about.
In our pursuit of better, cleaner, more readable test code, we have learned about Mockito annotations @Mock and @InjectMocks. Both can be used to cut down the boilerplate code related to the creation and
injection of mocks. By using them, we have:
shortened the setup phase of the test code,
got rid of repetitive, boilerplate test double creation and code setting.
However, in passing the responsibility for test double creation and injection over to Mockito, we must
agree to certain things, namely:
that the SUT must be created before injection happens (see the example in Listing 9.10),
that Mockito uses reflection, which can lower code coverage measures (and that it bypasses setters).
Using @Mock and @InjectMocks annotations might have both good and bad effects on the readability of
your code. On the one hand the code becomes more concise, and ceases to be cluttered up with repetitive
203
description
@BeforeSuite
The annotated method will be run before all tests in this suite have
run.
@AfterSuite
The annotated method will be run after all tests in this suite have run.
@BeforeTest
The annotated method will be run before any test method belonging to
the classes inside the <test> tag is runa.
204
description
@AfterTest
The annotated method will be run after all the test methods belonging
to the classes inside the <test> tag have run.
@BeforeGroups
The list of groups that this configuration method will run beforehand.
This method is guaranteed to run shortly before the first test method
belonging to any of these groups is invoked.
@AfterGroups
The list of groups that this configuration method will run afterwards.
This method is guaranteed to run shortly after the last test method
belonging to any of these groups is invoked.
@BeforeClass
The annotated method will be run before the first test method in the
current class is invoked.
@AfterClass
The annotated method will be run after all the test methods in the
current class have been run.
@BeforeMethod
@AfterMethod
<test> tag refers to part of the testng.xml file, which plays a role in one of the ways in which TestNG tests can be run.
Please refer to the TestNG documentation for detailed information on this topic.
Listing 9.11 shows a simple test which uses some of the aforementioned annotations. Listing 9.12 shows
the output of its execution. Please remember that the order of test methods execution is not guaranteed.
205
As shown above, methods marked with @BeforeClass and @AfterClass annotations are run, respectively,
before and after all tests of this class, while @BeforeMethod and @AfterMethod annotations are used,
respectively, for methods which are to be run before and after each test method.
In conclusion, let us mention that for purposes of unit testing you will probably only use a subset of
the TestNG annotations. However, do make sure you understand their purpose. This way you will be
able to take control over the creation of objects in your tests, which can help you avoid some bugs that
are hard to track down.
@BeforeMethod
public void setUp() {
sut = ...;
col = ...;
sut.setCollaborator(col);
}
sut.doA();
// assertions here
}
// assertions here
}
sut.doB();
public void testB() {
sut.doB();
// assertions here
206
// assertions here
}
}
The use of set-up methods for test fixture creation is heavily criticized by some developers. They point
out that by removing test fixture creation from the test methods, we make the test methods less readable:
i.e. they cannot be understood in isolation, but the reader also needs to go through the methods annotated
with @BeforeXYZ annotations. No doubt this is something we should be worried about!
On the other hand, creating the same SUT objects and collaborators in multiple test methods also has
its downsides. Test classes grow in length, and the DRY principle is violated. The readability of test
methods is also not perfect: they are often quite long and contain a lot of set-up logic (but everything
is in one place, which is a good thing).
And what is the correct answer to this riddle? I would say there are three factors in play here:
The DRY principle. If the DRY principle is very dear to you, you will probably use the set-up
methods approach. After you have got used to the fact that some of the test logic is also included within
set-up methods, you will have no problems reading your tests.
The readabilit of tests.
being self-contained.
On the other hand, if you are into BDD, you will rather enjoy your tests
Consistency. If you like your codebase to be written in the same way throughout, you will probably
want to follow one approach in all your tests. If this is not the most important factor, then you will
probably do what I did when writing tests for this book: use the set-up approach for test classes with
multiple test methods (and multiple collaborators), but put the test-fixture creation within test methods
in cases of shorter tests.
If you use the set-up methods approach, feel free to give them more intention-revealing names
than setUp()!
For the purposes of our discussion we will be using a simple Employee class. Let us assume that this class
is immutable7 - something which, in general, is a good thing. There is no point in showing the code of
Employee. For the sake of the ensuing discussion it will suffice to say that it has numerous fields (some
being primitives and some objects of the Address, Phone and Position types), and that all its fields are
initialized via a constructor (no setters).
This time we are not really interested in tests (assertion) as such, but only in that part of them which
is responsible for objects creation. An example of Employee objects creation within test code is shown
below.
Some properties of the Employee class, not important to the test cases, are reused between tests.
See http://en.wikipedia.org/wiki/Immutable_object
208
Both test methods contain similar, yet slightly different, code, responsible for the creation of an
employee.
Execution of the createEmployee() method.
There is nothing special about the code shown above. It is the kind of code that all of us have created
more than once. It is not especially nice or readable, but it serves its purpose. A private method
createEmployee() facilitates, at least to some extent, the creation of similar objects.
The test code shown in Listing 9.14 is aware of the details of the Employee class. There is no reasonable
abstraction which would make reading the code easier. All we really want to do in the test methods is
create a project manager and a CEO. But it is not possible to do this "just like that" - we need to go
deep into some properties of the Employee class to achieve this simple thing. This lowers the readability
of the test code.
Looking at the code in Listing 9.14, we can predict its future evolution. Probably some more static values
will be used (e.g. are start and end dates important? - if not they will end up as static values). During the
implementation of more sophisticated test scenarios, it will transpire that some properties of employees,
e.g. mobile phone, will become important. Then, new private utility methods will be created, to make
it possible to create employees with certain fields set with default or custom values. Private methods
will start to call one another (code reuse is good, is it not?) and the code will grow. Very soon, working
with it will not be a pleasure anymore.
The immutability of objects, which in general is a good thing, makes creating multiple objects
of the same kind rather cumbersome. You cannot reuse an object created in one test method
(or in some "setup" section) and change some of its properties using setters. If the Employee
class had not been immutable, then it would have been easier to reuse it across tests. In the
ensuing sections we will learn how to make immutability less difficult to work with.
209
The above code is much clearer, and does not delve into the implementation details of the Employee
class. All this is enclosed within the ObjectMotherEmployee class. This kind of separation of concerns
between test code and objects creation code is definitely a good thing.
In some implementations, Object Mother goes beyond the standard factory pattern by providing methods
which facilitate changing objects during tests. For example, an addAddress() method can be used to
simplify the setting of a new employees address. It can even work with an immutable Employee class:
for example, by copying data from one Employee object into another, via a constructor.
On the downside, let us note that the ObjectMotherEmployee class might soon become quite bloated.
Eventually, we may end up with numerous Object Mothers (calling one another), or with an Object
Mother with plenty of methods (making it a God Object9) - hard both to understand and to maintain.
See http://www.oodesign.com/factory-pattern.html
See http://en.wikipedia.org/wiki/God_object
210
Each field of the Employee class is represented by a setter method which returns an instance of
EmployeeBuilder. This allows us to chain the methods in any order.
The build() method calls a constructor of the Employee class and returns the result of the creation.
In addition to EmployeeBuilder, we also need builders for all of the other domain classes that will be used
(by composition) by the Employee class. Such builders would be very similar to the EmployeeBuilder
class we were discussing earlier. Listing 9.17 provides an example of another builder.
211
What is interesting in Listing 9.17 are its start() and end() methods. They take integers (year, month,
day) as parameters, which, as we shall see in a minute, make them easier to use. By using primitives in
the API of this builder, we free up its clients from being involved in the cumbersome process of creating
Date objects.
Let us now take a look at how two such builders might be used in tests. This is shown in Listing 9.18.
212
Here we have a utility method which creates a "typical" employee, that will then be modified
further. Please note, this method returns an EmployeeBuilder.
When creating objects, the anEmployee() utility method is used. This allows us to express things
like "CEO is an employee but with such and such properties", etc.
If objects of other types are required, their builders are created and called.
The use made here of the start() and end() methods of PositionBuilder is very simple indeed.
There is no need to create objects of the Date type.
I remember when I first saw this pattern in action: it felt very awkward to me. Back then, I found this
kind of code hard to read. But that was only a first impression. After some time spent studying this
pattern, I discovered that it confers several benefits:
In contrast to private methods with multiple parameters, in the case of Test Data Builders the meaning
of each value is very clear. There is no confusion about what the name of a person or street, the title
of a song, etc., is. Every value can be easily recognized by the method name it is passed to.
The test code can be read without problems (once you get used to it). It is clear what the properties
of each created object are.
Even though the Employee objects are immutable,
can reuse and modify them.
EmployeeBuilder
Writing such code is a pleasurable experience, because the IDE will prompt you with auto-complete
hints.
213
9.8.3. Conclusions
In this section we have taken a closer look at how more complex objects could be created within test code.
First, a "natural", unstructured approach was presented. This approach can be recommended only for
very simple domain models. If used for the creation of many different complex objects, then the test
code will be very hard to understand and maintain.
Then we introduced an Object Mother pattern. It encapsulates objects creation code and provides some
intention-revealing methods. Thanks to this the test code itself is free of objects creation code. However,
it does not remove the real source of the problem: instead it moves it from the area of test code to that
of utility classes. Compared to the first approach, this one requires only a minimal additional amount
of coding.
The last approach we adopted was that of using Test Data Builders. This gave us a lot of flexibility in
creating objects, but at the price of maintaining some additional code (much larger than in the case of
Object Mother). I would recommend this approach for complex domain objects.
When creating domain objects for your tests starts to get painful, it might mean that they
are too complicated.
9.9. Conclusions
In this chapter you will have learned some things about the organization of tests. We started with basic
matters. First, we compared two options for using packages for test classes. Then we looked at the pros
and cons of using class-level and method-level @Test annotations. After discussing a naming schema
for test classes (ClassNameTest) and test methods (should()), we also tackled the topic of comments
within test code.
Things got harder, then. We discussed a slightly different approach to writing tests, called BDD. In fact,
BDD is much more than this - it is a different mindset, which pays a great deal of attention to fulfilling
customers requirements. This topic is huge, but here we have concentrated exclusively on its influence
on how unit tests should be written.
After this we went on to discuss ways of removing some redundant code from Mockito-powered tests,
and took a look at the creation of a couple objects - both of them capable of saving us from writing some
lines of code, and of making our tests easier to maintain.
10
http://code.google.com/p/make-it-easy/
214
215
9.10. Exercises
In addition to the exercises presented below, do not forget to read some more about Behaviour Driven
Development! Many tools and ideas, especially for integration and end-to-end tests, are based on the
BDD approach.
216
217
Below, in Listing 10.1, an example of a suboptimal test of the BankAccount class is presented. Each test
method attempts to test a single method of the public API of BankAccount: getBalance(), deposit() and
withdraw().
In order to better present the main issue of this section, I have decided to keep all tests truncated to a
very limited number of test cases. In reality, I would use many more test cases, probably employing
parametrized tests (see Section 3.6).
219
Listing 10.1. One test method per one production code method
@Test
public class BankAccountTest {
private BankAccount account;
@BeforeMethod
public void setUp() {
account = new BankAccount();
}
public void testBalance() {
account.deposit(200);
assertEquals(account.getBalance(), 200);
}
public void testDeposit() {
account.deposit(100);
assertEquals(account.getBalance(), 100);
account.deposit(100);
assertEquals(account.getBalance(), 200);
}
public void testWithdraw() {
account.deposit(100);
account.withdraw(30);
assertEquals(account.getBalance(), 70);
account.withdraw(20);
assertEquals(account.getBalance(), 50);
}
}
Test for the getBalance() method. Note that it also uses a deposit() method.
Test for the deposit() method. It also calls getBalance().
Test for the withdraw() method, which likewise also calls getBalance().
As Listing 10.1 shows, isolation is not possible in unit tests at the level of methods. Each test method
calls various methods of the SUT - not only the one they have pretensions to testing. It has to be like
that, because you really cannot test the deposit() method without checking the accounts balance (using
the getBalance() method).
There are also some other issues with this approach. Let us list them:
If any of the test methods should fail, then an error message (e.g. "testDeposit has failed") will not
be informative enough for us to instantly understand which of the SUTs requirements has not been
fulfilled (where this is really important from the clients point of view).
Each of the SUTs methods is involved in multiple user-stories, so it is very hard to keep a "one test
method per production code method" pattern. For example, how might we add a test to the existing
code, which would verify that after creation an account has a balance of zero? We could enhance the
testBalance() method with an additional assertion, but that would make it prone to fail for more than
one reason. Which is not good, and leads to confusion when the test does fail.
Test methods tend to grow as the SUT is enhanced to reflect new requirements.
Sometimes it is hard to decide which of the SUTs methods is really being tested in a certain scenario
(because more than one is being used).
220
There is no test for the getBalance() method, because its proper functioning is validated by other
tests.
221
New methods added. This was possible, because the developer was thinking in terms of the SUTs
responsibility.
The two versions of the BankAccountTest test class differ substantially when it comes to test methods
naming. Good test method names include information about the scenario they verify. This topic is
discussed in detail in Section 9.3.2.
Table 10.1 compares what was tested and how, with both approaches.
testing
implementation
testing behaviour
when opening a
new account, its
balance should be
zero
shouldBeEmptyAfterCreation()
it is possible to
credit an account
testDeposit()
it is possible to
debit an account
testWithdraw()
and
shouldAllowToDepositMoney()
testBalance()
shouldAllowToWithdrawMoney()
shouldNotAllowToWitrdrawFromEmptyAccount(),
shouldNotAllowToUseNegativeAmountForDeposit()
and
shouldNotAllowToUseNegativeAmountForWithdraw()
One might be tempted to claim that this is just a single example, and a biased one at that. Well actually,
no. I have witnessed this far too many times to have any doubts about it being how things are: when
testing implementation only a subset of scenarios is being verified, test methods are overlapping,
and are prone to grow to include all possible scenarios for each test method. The key is to think about
222
223
As shown in Listing 10.4, a client has to do some complex calculations in order to obtain the result.
For each fund it needs to:
3
The example is only a slightly modified version of a real business domain problem and real code that once got implemented as part
of some long-forgotten project.
224
See http://en.wikipedia.org/wiki/Information_hiding
Please consult [martin2008] for a different approach - the Boy Scout Rule rule: "Leave the campground cleaner than you found it.".
225
int NB_OF_UNITS_AX = 5;
int NB_OF_UNITS_AY = 1;
int NB_OF_UNITS_BX = 4;
int NB_OF_UNITS_BY = 1;
BigDecimal FUND_A_VALUE = new BigDecimal(3);
BigDecimal FUND_B_VALUE = new BigDecimal(2);
@Test
public void totalValueShouldBeEqualToSumOfAllFundsValues() {
Client client = new Client();
IFund fundA = mock(IFund.class);
IFund fundB = mock(IFund.class);
IRegister regAX = mock(IRegister.class);
IRegister regAY = mock(IRegister.class);
IRegister regBX = mock(IRegister.class);
IRegister regBY = mock(IRegister.class);
ICurrentValue currentValueA = mock(ICurrentValue.class);
ICurrentValue currentValueB = mock(ICurrentValue.class);
...
Some primitive values that are also required for this test.
A client: our SUT.
The SUTs collaborators - direct and indirect.
Do We Need Mocks?
In the example as presented so far, we have used test doubles for all collaborators of the Client class.
In fact, a few lines of test code could have been spared, if we had used real objects instead of classes.
True, but on the other hand:
as discussed in Section 5.5, this would be no more than a short-term solution,
in real life, the values of funds might be fetched from some external source (e.g. a web service), which
would make it much harder to test.
Because of this, replacing all collaborators with test doubles seems a valid choice.
227
Wow, this differs substantially from what we were seeing before. The test is concise and does not contain
any information on the internalities of funds. Pursuing this object-oriented approach further, we would
have to write tests for each and every class (e.g. we need a test for implementation of the IFund interface,
and also for the IRegister interface), but all of them would be very, very simple indeed. Each of these
tests would also depend only on the SUT. No information about other classes would be used within the
test code. This is very different from what we saw in Listing 10.5.
Coming back to the question we asked when discussing a non-object-oriented version of this test, would
it be hard to write tests for 0, 1 and 7 funds? This time the answer is no. It would not be.
228
10.3.5. Conclusions
As the code examples within this section have demonstrated, bad code makes it hard to write tests.
Allow me to back up this claim with two quotes, illustrating the most important points connected with
what we have just been discussing.
Consistency. It is only a virtue, if you are not a screwup.
Wisdom of the Internet ;)
The misery begins with a single, innocent-seeming line such as "ask object x for the value of y (x.getY())
and make some decisions based on the value of y". If you encounter code which breaches the "Tell,
Dont Ask!" principle, then do not copy and paste it into your code. What you should do, instead, is
clean it, usually by adding methods in places where they ought to be6. Then proceed - writing clean,
well-designed code.
Do not copy other sloppy work! Do not become one of the blind led by the blind! An abyss
awaits you if you do. (Wow, that has really got you scared, hasnt it?)
If you need more information about this, please read about the "Feature Envy" code smell.
This is exactly the behaviour that mutation testing takes advantage of; see Section 11.4.
229
stubbing of a DOC,
asserting on the SUTs functionality,
verifying the DOCs behaviour.
If this test truly sets out to verify that "items are available if they are in store" (as the test method name
claims), then what is the last verification doing? Does it really help to achieve the goal of the test? Not
really. If this cooperation with the store collaborator is really a valuable feature of the SUT (is it?), then
maybe it would be more appropriate to have a second test to verify it:
230
Each of the tests in Listing 10.10 has only one reason to fail, while the previous version (in Listing 10.9)
has two. The tests are no longer overspecified. If we refactor the SUTs implementation, it may turn out
that only one fails, thus making it clear which functionality was broken.
This example shows the importance of good naming. It is very hard to decide which part of
the testShop() method is not relevant to the tests principal goal.
Another test-double based example is the use of specific parameter values ("my item", 7 or new
8
Date(x,y,z)) when something more generic would suffice (anyString(), anyInt(), anyDate()) . Again,
the question we should ask is whether these specific values are really important for the test case in hand.
If not, let us use more relaxed values.
Also, you might be tempted to test very defensively, to verify that some interactions have not
happened. Sometimes this makes sense. For example in Section 5.4.3 we verified whether no messages
had been sent to some collaborators. And such a test was fine - it made sure that the unsubscribe feature
worked fine. However, do not put such verifications in when they are not necessary. You could guard
each and every one of the SUTs collaborators with verifications that none of their methods have been
called9, but do not do so, unless they are important relative to the given scenario. Likewise, checking
whether certain calls to collaborators happened in the order requested (using Mockitos inOrder()
method) will usually just amount to overkill.
We can find numerous examples of overspecified tests outside of the interactions testing domain, as
well. A common case is to expect a certain exact form of text, where what is in fact important is only
that it should contain several statements. Like with the example discussed above, it is usually possible to
divide such tests into two smaller, more focused ones. For example, the first test could check whether a
message that has been created contains the users name and address, while the second one might perform
a full text-matching. This is also an example of when test dependencies make sense: there is no point in
bothering with an exact message comparison (which is what the second test verifies), if you know that
it does not contain any vital information (verified by the first test).
Based on what we have learned so far, we can say that a good rule of thumb for writing decent, focused
tests is as follows: test only the minimally necessary set of features using each test method.
231
10.4.3. Conclusions
The mime: Developing the code first and then repeating what the code does with
expectations mocks. This makes the code drive the tests rather than the other way around.
Usually leads to excessive setup and poorly named tests that are hard to see what they do.
James Carr
As with many other things related to quality, how you start makes a difference. If you start with
production code, then your tests will (inevitably, as experience proves) contain too many implementation
232
Let us take the example of simple getter/setter methods, as shown in Listing 10.11.
233
Yes, you definitely can write a test for this code - but please ask yourself: what kind of bugs, current
or future, do you expect to catch by having such a test?
In my opinion there is no sense to writing tests for such code after the code has already been written.
There are two reasons for this, which are as follows:
there is no logic there worth testing,
the code has probably been generated by the IDE (which then eliminates the threat of a silly
copy&paste error).
However, if the getter and setter methods are to be changed, entailing that some complexity will be added
(even of the simplest sort), then a test should be created. For example, if the setName() method evolves
and takes care of validation, along the lines shown in Listing 10.12, then it surely should be tested.
Many people argue that because of the possible future evolution of code (which is hard to predict when
the first version is actually being written), you should write a test even for such trivial cases as the first
version of the setName() method (the one without validation). I tend to disagree, and I would encourage
you to refrain from writing such tests. On the other hand, once things get complicated it is crucial to
write them. Then there is no excuse, and tests have to be written.
It is true that adding tests for even these simple methods guards against the possibility
that someone refactors and makes the methods "not-so-simple" anymore. In that case,
though, the refactorer needs to be aware that the method is now complex enough to break,
and should write tests for it - and preferably before the refactoring.
J.B. Raisenberg JUnit FAQ
However, none of this matters if you write code test-first. In that case, every method will be preceded
with a case of a test failing. The complexity does not matter. If it exists, there must be a test for it. It does
not necessarily mean that your test code will be full of trivial getter/setter tests. On the contrary, when
your design is being guided by tests, you might well find yourself writing less getters and setters than
234
True, proper testing of such simple code does require some effort. If you are to use test doubles (which
you probably should do), then the test will probably be longer, and even more complicated, than the
tested method itself. This will definitely discourage us from writing unit tests - especially in cases where
the benefits are not clearly visible. There is no easy answer to the question of whether you should write
a test for such a method. It depends on (at least) three factors, namely:
the type (i.e. specific features) of the Collaborator class,
the complexity of the delegating method,
the existence of other types of test.
Let us concentrate on these three factors, and run through a few comments that seem relevant to the issue:
there is usually (if not always) something more involved than simply telling the collaborator to do
the job. A delegating method will take some arguments and pass them to the collaborator, often
performing some actions before it does so (validation of parameters, creation of some objects based
on received parameters, etc.).
the collaborators
diverse ways,
doSomething()
method will often return some values being used by the SUT in
a collaborators doSomething() method might throw exceptions, which will somehow have to be
handled by the SUT,
other types of test - e.g. integration tests - might cover this functionality. For example, an integration
test might check if a class of service layer delegates tasks to a class of dao layer. However, it is rare
for integration tests to cover all the possible scenarios (i.e. exceptions thrown by collaborators), so
there might still be some gasps to be filled by unit tests.
My point is that the rather simple appearance of such delegating methods may be deceptive. There can
be much more to them than meets the eye. By thinking about possible usage scenarios and interactions
between the SUT and collaborators, you can reveal this hidden complexity and test it. But, as has already
been said, every instance of such code can be considered individually, and there might be cases where
writing a test is a waste of time.
235
10.6. Conclusions
Among the topics discussed in this chapter, there are two fundamental things that I would like you to
remember. The first is the "Test behaviour, not implementation!" rule: if you stick to this, it will guide
you towards high-quality testing (on every level, not only for unit tests). The second can be expressed by
two rules that apply to production code, commonly known as the Law of Demeter and the Tell, Dont
Ask! principle. Expect trouble when testing code that does not abide by either of them.
The rest of this chapter has been devoted to problems of logic within test code, the notion of "things that
are too simple to break", and to the problem of test maintenance.
236
10.7. Exercises
10.7.1. A Car is a Sports Car if
After three months of analysis a team of business analysts have decided that a car can be marked with
the "sports" tag if it satisfies all of the following requirements:
it is red,
it was manufactured by Ferrari,
its engine has more than 6 cylinders.
Based on these detailed requirements a team of top-notch developers have come up with the following
implementation of the CarSearch class:
237
Your task is to write some tests for the findSportCars() method of the CarSearch class. Basically, what
you have to do is pass some cars to the CarSearch class (using its addCar()) method, and then verify,
whether only sports cars are being returned by the findSportsCars() method.
Initially, do this for the original implementation of the CarSearch class. Then, redesign the Car interface,
so that the CarSearch class does not violate either the "Law of Demeter" or the "Tell, Dont Ask!"
principles, and write the tests once again. Compare the amount of work involved in each case
10
See http://en.wikipedia.org/wiki/Stack_%28abstract_data_type%29.
238
11.1. An Overview
When talking about quality we should always ask "if" before we ask "how". Questions like "would I be
better off writing an integration test or a unit test for this?", or "do I really need to cover this scenario
isnt it perhaps already covered by another test?", should come before any pondering of the design and
implementation of test code. A useless and/or redundant test of the highest quality is still, well, useless
and/or redundant. Do not waste your time writing perfect tests that should not have been written at all!
In the rest of this chapter we shall assume that a positive answer has been given to this first "if" question.
This is often the case with unit tests which, in general, should be written for every piece of code you
create.
Test Smells
When dealing with production code, we use the "code smell"1 to refer to various statements in code that
do not look (smell) right. Such code smells have been gathered, given names and are widely recognized
1
http://en.wikipedia.org/wiki/Code_smell
239
Refactoring
When talking about code smells, we can not pass over the subject of refactoring. We have already
introduced the term and given some examples of refactoring in action, when describing the TDD rhythm.
In this chapter we will discuss some refactorings of test code. As with production code refactoring,
refactorings of test code help to achieve higher quality of both types: internal and external. Internal,
because well-refactored tests are easier to understand and maintain, and external, because by refactoring
we are making it more probable that our tests actually test something valuable.
At this point a cautious reader will pause in their reading feeling that something is not quite
right here. True! Previously, I defined refactoring as moving through code "over a safety net
of tests", whereas now I am using this term to describe an activity performed in the absence
of tests (since we do not have tests for tests, right?). Yes, right! It is actually a misuse of the
term "refactoring" to apply it to the activity of changing test code. However, the problem is
that it is so commonly used this way that I dare not give it any other name.
http://pmd.sourceforge.net/
http://findbugs.sourceforge.net/
4
At this point I would like to encourage you to read the list of TDD anti-patterns gathered by James Carr - [carr2006]
3
240
assertions
have
assertEquals(someBoolean,
assertTrue(someVariable ==
been
used,
e.g.
true),
and
null),
assertTrue(someBoolean)
assertNull(someVariable)
instead
instead
of
of
241
http://en.wikipedia.org/wiki/Cyclomatic_complexity
See http://en.wikipedia.org/wiki/Code_coverage
9
See http://en.wikipedia.org/wiki/Software_metric, and especially http://en.wikipedia.org/wiki/Cyclomatic_complexity, for more
information on this topic.
8
242
Table 11.1 shows calls to foo() methods, which should be issued from the test code, in order to obtain
100% line and branch coverage respectively.
branch coverage
foo(true, true)
foo(true, false)
foo(true, true)
foo(false,false)
Now that we understand the types of code coverage provided by Cobertura, let us take a look at the
results of its work.
See http://en.wikipedia.org/wiki/Code_coverage
http://cobertura.sourceforge.net/
12
The code used to illustrate line and branch coverage is based on Wikipedia example: http://en.wikipedia.org/wiki/Code_coverage
11
243
Figure 11.1 presents an overview of some project coverage. For each package the following statistics
are given:
the percentage of line coverage, along with the total number of lines and number of lines covered,
the percentage of branch coverage, along with the total number of branches and, for purposes of
comparison, the number of branches covered.
As you might guess, a red color is used for those parts of the code not executed (not "covered") during
the tests. So - the more green, the better? Well, yes and no - we will get to this soon.
The report shown in Figure 11.2 gives an overview of code coverage for the whole package, and for
individual classes of the package. As with the previous report, it gives information on line and branch
coverage. Figure 11.3 provides an example.
244
Figure 11.3 presents code for our old friend - the Money class. This report shows precisely which parts of
the Money class are covered by tests. The green color denotes parts that have been tested, the red those
not executed during the tests. The first column of numbers is the line of code, while the second gives
some additional information, about the number of times each line was "touched" during the testing. For
example, in the case of line 12 (the if statement) the number on a red background says 1. This means
that this if statement has only been executed once. We may guess that the current tests contain only one
case, which makes this if evaluate to true. If we were to add another test which evaluated this Boolean
expression to false, then the number 1 on a red background would change to 2 on a green background.
Also, the coverage of line 17 would change from 0 to 1 (and from red to green).
245
Please note that there are many important features of the Money class that we are still not verifying. For
example, it would be nice to make sure that objects of the Money class are immutable, but if you think
about such a test, it would not make the code coverage any higher. We would also like to make sure the
addition really works, by verifying it with some more examples. But no, we have not done anything like
this, and yet voila! - we already have 86% line coverage and 75% branch coverage.
This simple example reveals a very important weakness of code coverage measures. Code coverage
tools do not measure whether tests cover requirements! They only measure what parts of the
production code were executed when running the tests.
11.3.5. Conclusion
Code coverage tells you what you definitely havent tested, not what you have.
Mark Simpson StackOverflow discussion 2009
In this section we have seen the two faces of code coverage. The first face is friendly and helpful. It
allows you to get a good understanding of the parts of the code which are not covered by tests and thus
find the gaps in your safety net. However, there is also another face to code coverage. This one makes
you worry about seeing the color red on coverage reports and waste time writing tests for lines that are
not worth it. It also makes you feel secure, and makes you believe that your code works as required
(when neither of these are in fact justified).
The point is, that you should choose what is good in code coverage and ignore the rest. You should
use it to:
13
247
http://pitest.org
In fact, if all tests still pass, it can also mean that the "mutant" program is equivalent in behaviour to the original program.
16
Okay, I admit it: this heuristic sounds like it was taken from the game series Fallout: "the more dead mutants, the better" :).
15
249
Let us say that we also have a test class which (supposedly) verifies the correctness of the
method:
twoIfs()
What is really interesting is that this simple test is good enough to satisfy the code coverage tool - it
achieves 100% in respect of both line and branch coverage! Figure 11.4 shows this:
17
The idea of this code is taken from the StackOverflow discussion about code coverage pitfalls - http://stackoverflow.com/
questions/695811/pitfalls-of-code-coverage.
250
When we execute a PIT analysis, it will create mutants of the production code from Listing 11.4 by
reverting the inequality operators and fiddling with comparison values. Then it will run all tests (in our
case only the one test shown in Listing 11.5) against each mutant and check if they failed.
The outcome report shows the code that was mutated together with some information about applied
mutations. Just like with code coverage reports, the red background denotes "bad" lines of code, which
means that some mutations performed on these lines went unnoticed when testing. Below the source code
there is a list of applied mutations. From this list we can learn that, for example, one mutant survived the
change of conditional boundary in line 6. The "greater than" symbol was changed to "greater or equal"
and the tests still passed. The report informs us that such and such a mutant SURVIVED, which means it
was not detected by our tests.
251
This simple example shows the difference between code coverage and mutation testing: in short, it is
much simpler to satisfy coverage tools, whereas mutation testing tools can detect more holes within
your tests.
11.4.3. Conclusions
Mutation testing has been around since the late 1970s but is rarely used outside academia.
Executing a huge number of mutants and finding equivalent mutants has been too
expensive for practical use.
Mattias Bybro A Mutation Testing Tool For Java Programs (2003)
Mutation testing looks interesting, but I have never once heard tell of it being used successfully in a
commercial project. There could be many reasons why this idea has never made it into developers'
toolboxes, but I think the main one is that for a very long time there were no mutation testing
tools that were production-ready. Existing tools were lagging behind relative to the progress of Java
language (e.g. not supporting Java 5 annotations), and/or were not up to the industry standards and
developers expectations in terms of reliability and ease of use. Because of this, code coverage, which
has had decent tools for years, is today a standard part of every development process, while mutation
testing is nowhere to be found. As for today, developers in general not only know nothing about such
tools, but are even unaware of the very concept of mutation testing!
This situation is likely to change with the rise of the PIT framework, which offers much higher usability
and reliability than any other mutation testing tool so far. But it will surely take time for the whole
252
The situation here changes rapidly - for example, a plugin for Sonar is already available: http://docs.codehaus.org/display/SONAR/
Pitest.
19
As far as I know, this issue is being treated very seriously by mutation testing tools authors, and a lot of improvements have already
been made. For example, these tools can select a tiny subset of the potentially "strongest" mutants and only execute tests against
them, thus significantly reducing the testing time.
253
Size Heuristics
Some idea of test code quality might be gained by looking at the following features of the test code:
the number of imported classes,
the number of test doubles used,
the length of set-up methods,
the length of test methods,
the length of test class.
It is not possible to come up with exact numbers here - which should trigger a red light in your head.
However, common sense is usually enough to distinguish right from wrong. For example, three test
doubles in a test class are probably fine, but if there are eight of them, then an alarm bell should ring.
And what about four, five, six or seven test doubles? Where is the exact border? As usual, "it depends",
and you need some more time to decide whether or not things are fine. The same holds true for the
number of imports (and the variety of imported classes).
As for the length of the test methods and classes, here, again, common sense should be sufficient.
Once again, please remember that finding weaknesses in any of the above might be a
symptom of bad production code, which is only reflected by the test code. Violations of
reasonable size values for test code usually indicate that the class being tested has too much
responsibility.
Conclusions
Three minutes will not allow you to perform a real test code review, but it is enough to uncover some
major issues with the test code. If this is all you can have at the moment, then fair enough - it is still
much better than nothing.
Easy to Understand
A good unit test is easy to understand. But its readability can be spoilt by many small issues, which
you should look out for.
A good test method has a content-revealing name, which gives information on the particular scenario
implemented within it (see Section 9.3). Similarly, variables used in tests should be easy to understand:
for example, can you tell which variable is an SUT and which are collaborators? Also, variables used
within test code should inform you precisely about what their role is: are they here only to satisfy the
API of the method being tested, or are they crucial to triggering some behaviour of the SUT or its
collaborators? (see Section 11.6.3).
Are the test methods short and focused? They should test a particular feature of the SUT (see Section
10.1), and nothing more. Look for anything that goes beyond just the simplest actions (arrange/act/
assert).
20
Please, do not take these values literally! They are only meant to be illustrative. See Section 11.3 for more information on desired
code coverage levels.
255
Documented
Well-written unit tests usually do not need documentation (see Section 9.4). However, it sometimes
transpires that you come across things which you wish had been documented, but are not. For example,
the selection of test cases might not be obvious (e.g. "why is this method validated against Dubai and
Sydney timezones?"). Probably there is some business explanation for this, which should be added as a
comment (sometimes a link to bug tracker issue is all that is required). If it is not there, then you cannot
determine whether the test cases are covering all the important scenarios.
Run Them
Some of the issues relating to running tests during code reviews have already been discussed. However,
it is now time to have a closer look at them.
Remember, always execute the tests which are under code review.
Take a look at the build script. See if there are any conditions under which tests are not run (e.g. Maven
profiles). Make sure the tests are not skipped.
257
Date Testing
Experience tells me that the testing of time-dependent business logic is rarely done correctly (see Section
6.8). Common issues you should look for are the following:
Look for any Thread.sleep() code constructs which make unit tests run longer than is really required.
A common mistake is to test only the current date, which means the bug will be discovered exactly
on the day the code fails in production. In general you need to make sure all test cases are covered.
11.5.3. Conclusions
Of the many approaches to ensuring the quality of your test code, code reviews are to be recommended
the most strongly. They help to find bugs, help your team to converge with respect to how they all go
about coding, and serve to disseminate knowledge amongst team members about parts of the software
being developed. Moreover, by examining the test code, a lot can be discovered about production code.
Frankly, what more could one ask for? The only downside is that to perform a thorough examination
of test code, a lot of time is required.
I strongly recommend making test code reviews a part of your teams working routine. Code reviews
should belong to your Definition of Done, and they should embrace test code in the same manner that
they embrace production code.
Please note that this approach is exactly the opposite of what you do when refactoring production code, which should be performed
only if all tests are green.
259
The problem here is that this test is not obvious. For someone who looks at the test for the first time, it is
not obvious whether user_2 should or should not have been granted the READ permission. Who the heck
is user_2? Well, this must be checked by analyzing the data of previously registered users (probably in
a setUp() method somewhere).
A simple change can achieve wonders. Look at the updated version shown in Listing 11.7.
260
Listing 11.7. Admin, logged on user, guest - I know who you are!
@DataProvider
public static Object[][] usersPermissions() {
return new Object[][]{
{ADMIN, Permission.READ},
{ADMIN, Permission.WRITE},
{ADMIN, Permission.REMOVE},
{LOGGED, Permission.WRITE},
{LOGGED, Permission.READ},
{GUEST, Permission.READ}
};
}
@Test(dataProvider = "usersPermissions")
public void shouldReturnTrueIfUserHasPermission(
String username, Permission permission) {
assertTrue(sut.hasPermission(username, permission));
}
Now this is clear! Admin should have all possible permissions. A "normal" logged on user should
be able to read and write, but not to remove things. A guest user can normally only see what others
have uploaded, but cannot change the content himself or herself. There is no need to consult any
documentation: the code speaks for itself.
What properties does a server variable have? What kind of server is created? If you do not remember
the API of MockServer, then you need to ask your IDE for help, so it explains the meaning of true and
false flags being passed to the MockServer constructor. Would it be possible to change this code so it is
easier to understand? Yes, by introducing some values whose names tell a story:
Now this makes more sense - this server responds with a file, and does not use SSL.
Another way in which this code could be made more readable is by using the Test Data
Builder pattern (see Section 9.8.2).
261
There is nothing wrong with this test method, except that it is not clear whether firstname and lastname
are of any importance to the logic being tested. This can be fixed by giving them values which make
them convey the message explicitly: "we are not important, you should not care about us". The code
below illustrates how this can be achieved:
I usually use an ANY_ prefix, and capital letters only - but this is just one possible instance of
how one might do this. Find something which looks good for you.
Apart from reading the test code more easily, another advantage is that if the test fails, the error message
will also clearly show what is important:
In the event of a value like this being used repeatedly in multiple test methods, I would suggest extracting
it as a constant (as you should always do), as well as naming it appropriately:
262
Listing 11.13. Irrelevant data expressed by both variable names and values
private static final String ANY_NAME = "ANY_NAME";
private static final String ANY_SURNAME = "ANY_SURNAME";
@Test
public void kidsNotAllowed() {
Person kid = new Person(ANY_NAME, ANY_SURNAME);
kid.setAge(12);
assertFalse(kid.isAdult(), kid + " is a kid!");
}
This renaming of constants is especially important for values other than String, so you can have variables
like: ANY_VALID_POST_CODE, ANY_NUMBER, ANY_DATE, etc.
In fact, there is no need to wait for the refactoring phase to make irrelevant data clearly visible. When
writing a test you should be clear in your mind about which data is important for the scenario you are
covering with that test. This is probably the best time to introduce names of variables and values along
the lines discussed in this section.
assertEquals()
assertTrue()
and
assertFalse().
See http://martinfowler.com/refactoring/catalog/extractMethod.html
265
11.7. Conclusions
In this chapter we have worked hard to determine precisely how to measure and improve test quality.
As developers, we love tools which can do something for us, and that is why we started out with a
discussion of various tools - static code analyzers (see Section 11.2), code coverage (see Section 11.3)
and mutation testing (see Section 11.4). We discovered what, exactly, they are good at when it comes
to helping us achieve high-quality tests, but also realized how very inadequate they are.
Then we turned towards code reviews (see Section 11.5), and found these to be a great way of uncovering
the weak spots in our test code. Alas, code reviews take time, and what is more, not all developers
perform them well enough. Some developers lack knowledge about what to look for, some do not treat
test code with enough respect to bother analyzing it, and some are not allowed to "waste" their precious
time on such unproductive activities (no comment). Finally, we discussed various refactorings (see
Section 11.6) that could be implemented so that our tests will be more readable and more easily
maintained.
Several times in this chapter I have sought to highlight the various issues relating to achieving highquality tests. The picture I have tried to create is one in which having really good tests is definitely
possible, but is also something that calls for full commitment on your part. The tools can assist you with
this task, but they play only a secondary role.
In conclusion, here is a list of "action points" which should help you achieve the goal of high-quality
tests:
Treat test quality as the number-one issue from the very outset.
Take the refactoring phase of TDD very seriously.
Test code should undergo a code review in the same way that production code does. You need
someone other than yourself to take a critical look at your tests.
"Do not live with broken windows"23 - bad things tend to get copied, and soon you will have much
more to clean than you can handle. Never delay fixing them.
Think hard about the test cases required (see Section 6.1) and follow the TDD approach in order
to cover all important functionalities with tests. This is much more important than trying to satisfy
requirements with respect to the measuring of code coverage!
Use code coverage to uncover untested areas.
23
266
267
11.8. Exercises
"Quality is free" they say24, but one has to work really hard to achieve it. The single exercise in this
section is intended to help you appreciate this simple fact.
The next two listings show test code of the Fridge class, which - after everything we have explored up to
now, and taking a mere glance at the code - we can say is a complete mess! It works, which means it tests
some features of the SUT, but it could have been much better written. I hope to never see anything like
this again in the rest of my life. Anyway, your task for now is to clean this mess! Use the knowledge of
high-quality testing you have gained from this chapter, but also refer to the examples given previously,
in order to rewrite this test! For example, you should probably take care of:
the proper naming of test classes, methods and variables,
the use of parametrized tests,
duplicated code,
and many more issues that are hidden there.
Make sure you do not loose any test case by redesigning this test class!
The two test methods of the FoodTesting class are shown below:
24
See http://www.wppl.org/wphistory/PhilipCrosby/QualityIsFreeIfYouUnderstandIt.pdf
268
269
270
SCM, Source Code Management, relates to all kind of software tools which allows one to track file versions. Commonly
used tools in software development are Subversion, CVS or Git. For more information see http://en.wikipedia.org/wiki/
Source_Code_Management.
272
By production-like environment I mean an environment that is as close as possible in every respect to a real production environment.
Ideally this should be the production environment itself, but that is rarely available for testing.
273
End-to-end tests vary a great deal, depending on the application you are writing, so it is hard to generalize about them.
http://improvingworks.com/products/infinitest
5
http://junitmax.com/
4
274
As far as Gradle and Maven are concerned, I will assume that your project has a layout compatible with
what was discussed in Section 3.1. The main requirement is that your production code resides in src/
main/java and test classes in src/test/java. Both Gradle and Maven treat this layout as the default. If
you use a different directory structure then you will need to inform your build tool about it. Please refer
to the appropriate documentation about how to do it.
One could ask why it is that we need to bother with build tools, if our powerful IDEs are capable of
running tests. The thing is, the tests we write will be executed on the machines of other developers (who
may be using different IDEs), and even on the IDE-free environment of a CI server. Having a build script
capable of running tests is the first step in helping to overcome the "it works on my machine" syndrome.
This appendix concentrates on running tests on your local machine. However, bear in mind
that every team should have a separate machine (a continuous integration server) dedicated
to the building (compiling, testing, packaging, etc.) of the code it is developing. Continuous
integration is well beyond the scope of this book, but there is plenty of information available
on the Internet if you need it.
275
If you prefer typing, then first make sure you have the correct test class in focus (i.e. that it is open in
the editor and the cursor is there, or that it is highlighted in Package Explorer). To run all tests from this
selected class, place the cursor somewhere outside any test method and press SHIFT+ALT+X followed
by N. If you want to run a particular test method, place the cursor on this method, and use the same
combination: SHIFT+ALT+X followed by N.
In order to rerun the same test (or tests), press F11.
276
If you prefer typing, then first ensure that you have got the right test class in focus (that it is open in
the editor and the cursor is there). To run all tests from this selected class, place the cursor somewhere
outside any test method and press CTRL+SHIFT+F10. If you want to run a particular test method, then
place the cursor on this method, and use the same combination: CTRL+SHIFT+F10.
In order to rerun the same test (or tests) press SHIFT+F10.
test
278
Listing B.3. Using a custom TestNG listener and reporter with Gradle
test {
useTestNG()
options {
listeners << 'com.practicalunittesting.DotTestListener',
listeners << 'fully.qualified.path.to.ExcelReporter'
}
}
Both listeners and reporters are registered identically. (Note the comma after the first line!)
At the time of writing the book a bug in Gradle prevents it from properly printing some
information to the System.out which may influence the work of your custom TestNG
listeners. It should be fixed in version 1.0, so it is very probable that it works fine now,
when you read these words. Anyway, if you plan to write custom listeners and run them with
Gradle, please see http://issues.gradle.org/browse/GRADLE-2058 to learn about the current
situation.
The configuration shown above would result in having TestNG, Hamcrest and some custom listeners
available on the test classpath.
279
Now execute mvn test from the command line. Maven will automatically recognize TestNG test classes
located in src/test/java and run them. You will see something similar to the following output (some
lines omitted):
http://maven.apache.org/plugins/maven-surefire-plugin/
http://maven.apache.org/plugins/maven-surefire-report-plugin/
3
http://maven.apache.org/plugins/maven-site-plugin/
4
http://maven.apache.org/plugins/maven-failsafe-plugin/
2
280
The last printed line assures us that all tests have passed successfully.
In the event of failed tests, Maven will print error messages to the console. Test results are kept in the
target/surefire-reports directory in text, and XML format. If you prefer something more readable,
Maven makes it simple to generate an HTML report as well. As was mentioned previously, you could
use the Maven Surefire Report Plugin or the Maven Site Plugin to achieve this.
281
Make sure you use the test scope so Maven adds them to the test classpath.
282
283
C.3. Stubbing
Some authors differ in their opinions as to whether test spies also have stubbing capabilities. However,
the majority, including Gerard Meszaros, the father of test doubles taxonomy, answer this question in
the affirmative. Mockito also provides stubbing capabilities for its test spies.
284
C.4. Forgiveness
There is a general idea that test spies are more "forgiving" than mocks. This means that test spies let
us specify which interactions are to be verified, and turn a blind eye to the rest. In fact, this is one
of the notable features of the Mockito test-spying framework. Its author, Szczepan Faber, promotes
such an approach as a way of testing only what should be tested at some given point in time, without
paying attention to interactions that are beyond the scope of that particular test1. The motivation behind
such behaviour is to avoid overspecified tests, which are a big problem to maintain (see Chapter 10,
Maintainable Tests). However, the idea is disputed within the community, and some people would rather
vote for stricter verification of the SUTs actions.
Without getting involved in the details of this debate, let us say that in general mock frameworks are
stricter than Mockito. However, some of them e.g. EasyMock - support both styles of testing. By
default, its mocks are "strict" (which means they fail tests if any unexpected interaction occurs), but also
allow one to use so-called "nice" mocks, which verify only selected interactions - exactly the way the
test spies of Mockito do.
To conclude, "forgiveness" is not supported by test spies exclusively, even though they do seem more
inclined towards it than mock objects.
There is some unclarity about how the terms "nice" and "strict" are to be understood when
used to characterize mocks. By "strict" mocks, [meszaros2007] has in mind mocks which will
fail if the received method calls are in a different order than the expected one. Mocks which
are "nice" or "lenient" will accept a different order, and only pay attention to the methods
and values of parameters. But based on my observations I would say that most other people
follow a different definition of the meaning of the terms "nice" and "strict" when used here
- exactly like that given previously in this section.
C.6. Conclusions
Historically, we all used mocks. They were mentioned in the title of the famous "Mock Roles, Not
Object" paper ([freeman2004]), which brought mocks to the masses, and for a long time no distinctions
between test doubles were made at all - we just called all of them "mocks". Today, things are different,
because we have learned from experience that there are, indeed, differences between test doubles. They
also exist between mocks and test spies - even though both can be used (almost) interchangeably.
There are some reasons why I would consider it preferable to use test spies rather than mocks. Of these,
the two most important are that they allow me to keep to the arrange/act/assert pattern, and that they
1
285
286
See http://coderetreat.org/
See http://en.wikipedia.org/wiki/Kata_%28programming%29
287
(http://
Involve yourself in some open-source project to collaborate with others on some cool features.
288
Bibliography
You cannot open a book without learning something.
Confucius
Books
[beust2007] Cdric Beust, Hani Suleiman, "Next Generation Java Testing: TestNG and Advanced
Concepts", Addison-Wesley Professional, 2007
[feathers2004] Michael Feathers. "Working Effectively With Legacy Code", Prentice Hall, 2004
[fowler1999] Martin Fowler, Kent Beck, John Brant, William Opdyke, Don Roberts, "Refactoring:
Improving the Design of Existing Code", Addison-Wesley Professional, 1999
[freeman2009] Steve Freeman, Nat Pryce. "Growing Object-Oriented Software, Guided by Tests (Beck
Signature)", Addison Wesley, 2009
[gof1994] The "Gang of Four": Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides, "Design
Patterns: Elements of Reusable Object-Oriented Software", Addison-Wesley, 1994
[goetz2006] Brian Goetz, Tim Peierls, Joshua Bloch, Joseph Bowbeer, David Holmes, Doug Lea, "Java
Concurrency in Practice", Addison-Wesley Professional, 2006.
[martin2008] Robert C. Martin. "Clean Code: A Handbook of Agile Software Craftsmanship", Prentice
Hall, 2008
[meszaros2007] Gerard Meszaros, "xUnit Test Patterns, Refactoring Test Code", Addison Wesley, 2007
Documentation
[testngJavadocs] TestNG javadocs, http://testng.org/javadocs/
[testngDocumentation] TestNG documentation, http://testng.org/doc/documentation-main.html
[mockitoJavadocs] Mockito javadocs, http://docs.mockito.googlecode.com/hg/latest/index.html
[mockitoDocumentation] Mockito documentation, http://docs.mockito.googlecode.com/hg/latest/org/
mockito/Mockito.html
[unitilsJavadocs] Unitils javadocs, http://www.unitils.org/apidocs/index.html
[unitilsDocumentation] Unitils documentation, http://www.unitils.org/
[hamcrestDocumentation] Hamcrest documentation, http://code.google.com/p/hamcrest/
[festJavadocs] FEST Fluent Assertions javadocs, http://fest.easytesting.org/assert/apidocs/index.html
[festDoocumentation] FEST Fluent Assertions documentation, http://fest.codehaus.org/Fluent+Assertions
+Module
289
Bibliography
Articles
[beck2008] Kent Beck, Just Ship, Baby, http://www.threeriversinstitute.org/JustShip.html
[bybro2003] Mattias Bybro, "A Mutation Testing Tool For Java Programs"
[carr2006] James Carr, TDD Anti-Patterns, http://blog.james-carr.org/2006/11/03/tdd-anti-patterns/
[faber2008] Szczepan Faber, "Should I worry about the unexpected?", http://monkeyisland.pl/2008/07/12/
should-i-worry-about-the-unexpected/
[fowler2007]
Martin
Fowler,
mocksArentStubs.html
"Mocks
Arent
Stubs",
http://martinfowler.com/articles/
[freeman2004] Steve Freeman, Nat Pryce, Tim Mackinnon, Joe Walnes. "Mock Roles Not Object", http://
www.jmock.org/oopsla2004.pdf
[north2006] Dan North, Introducing BDD, http://dannorth.net/introducing-bdd/
[ma2005] Yu-seung Ma and Jeff Offutt and Yong Rae Kwon, "MuJava : An automated class mutation
system."
[savoia2007] Alberto Savoia, How Much Unit Test Coverage Do You Need? - The Testivus Answer, http://
www.artima.com/weblogs/viewpost.jsp?thread=204677
290
Glossary
API
ATDD
BDD
CEO
CI
Continuous Integration
CPU
CSS
CSV
CVS
DAO
DI
Dependency Injection
DOC
Depended On Component
DRY
DSL
DTO
FAQ
GUI
HTML
HTTP
IDE
JAR
Java ARchive
JDBC
JDK
JNDI
JUG
JVM
Glossary
KISS
LDAP
LOC
Line Of Code
OO
Object-Oriented
ORM
Object-Relational Mapping
OSGi
PIM
PM
Project Manager
POJO
QA
Quality Assurance
SCM
SQL
SRP
SSL
SUT
TDD
UI
User Interface
XML
XP
EXtreme Programming
YAGNI
292
Index
A
access modifiers, 153
use in tests, 159, 160
accessor method
testing, 233
anti-pattern, 239
feature envy, 229
god object, 210, 225
mime, 232
Apache Commons Lang, 134
Apache POI, 178
arrange/act/assert
broken, 105
broken with mock, 283
definition, 34
expected exceptions, 108
with test spy, 283
assertions, 21, 22-24
for collections, 123
number of, 35, 123, 147-150
parameters order, 23
using matchers, 110
using the right one, 23, 184
assertions message (see failure message)
B
BDD, 197-200
and set-up methods, 207
introduction, 197
Mockito support, 199
with TestNG, 198
Behaviour Driven Development (see BDD)
boilerplate code, 200-204
Boy Scout Rule, 225, 259
bugs
fixing, 41
fixing cost, 9
build tools, 257, 275
C
catch-exception, 11, 108
classes
naming (see naming)
Cobertura, 11
reports, 243
code coverage, 242-248, 255, 257
100% goal, 246
D
data providers, 25-29, 54
dynamic, 27, 129
reuse, 27
debugging tests, 185
with Eclipse, 276
with IntelliJ IDEA, 277
delegator method
testing, 235
Dependency Injection (see DI)
design patterns
DTO, 95
factory
testing, 155
use in tests, 210
immutable object, 208, 209
object mother, 210-210
publisher/subscriber, 79
test data builder, 210-214
benefits, 213
Value Object, 95
developers tests
as documentation, 272
automation, 270, 273
comparison, 7, 239
pros & cons, 8
results, 22
types, 2
293
Index
when to run, 55, 273
when to write, 40-42
DI
use in testing, 157
direct inputs, 14, 15
direct outputs, 14, 15
DOC
creation, 66, 200, 207
definition, 3
examples, 6
in unit tests, 14
interactions with SUT, 14
not implemented, 89
real collaborators, 90-95, 227
documentation (see test documentation)
Dont Repeat Yourself (see DRY principle)
DRY principle, 46
and set-up methods, 207
cases against it, 265
test dependencies, 138
violation, 94, 207
DSL
test data builder, 210
with matchers, 128
dummy
definition, 75
example, 75, 81
dummy object (see dummy)
E
EasyMock, 11, 65, 68
code example, 283
Eclipse, 12
debugging tests, 276
running tests, 275
test reports, 171
end-to-end tests, 5
examples, 6
TDD, 48
test fixture examples, 32
Excel
reading test parameters, 128
writing test reports, 177
exceptions (see expected exceptions)
expected exceptions, 29-31, 185, 192
advanced, 104-109
message verification, 105
with FEST, 109
F
fail fast, 27, 284
test dependencies, 140-142
failure message, 56, 183-185, 220, 256, 262
custom message, 183
Hamcrest, 127
improving it, 51
matchers, 111
toString(), 184
Unitils, 125
when to write, 45, 60
fairy
dies, 229
fault injection (see mutation testing)
Feed4TestNG, 134
FEST, 11
assertions, 110
collections testing, 126
custom matchers, 110-112
expected exceptions, 109
Findbugs, 239, 241
flickering tests, 116, 119, 137
fluent interface (see FEST)
with FEST, 126
with test data builder, 210
fragile tests (see overspecified tests)
G
getter (see accessor metod)
getters
are evil, 229
given-when-then (see BDD)
Gradle, 12, 180, 275
running tests, 278
test reports, 174
tests classapth, 279
using listeners and reporters, 279
H
Hamcrest, 11
collections testing, 126-127
Mockito integration, 114
human testers, 272
I
IDE, 12, 171
autogenerated code, 44, 51, 61, 223
Eclipse (see Eclipse)
IntelliJ IDEA (see IntelliJ IDEAi)
294
Index
indirect inputs, 14, 16
controlling, 68, 76
indirect outputs, 14, 16, 283
verification, 69, 77, 77
information hiding, 225
inheritance, 256
integration tests, 4
examples, 6
TDD, 48
test fixture examples, 32
IntelliJ IDEA, 12
debugging tests, 277
running tests, 277
test reports, 173
interactions testing, 15-17, 96
example, 75
no interaction, 231
no interactions, 85, 88, 107
order verification, 231
vs. state testing, 16-17, 233
isolation, 13, 75
of test methods, 207
pros & cons, 90-95
with test doubles, 72
J
Java API
arrays, 123
Calendar, 119
Collection, 123
Comparable, 54, 55
equals(), 165
instanceof, 55
List, 123
Map, 123
reflection, 152
Set, 123
toString(), 184
Javadocs, 13, 47, 171, 272
JMock, 68, 118
JUnit
assertions, 23
differences with TestNG, 23
test methods names, 194
vs. test dependencies, 138
K
KISS principle, 46, 240, 256
L
Law of Demeter (see LOD principle)
legacy code, 7, 60, 151, 228
Linux, 12
listeners (see test listeners)
LOD principle, 223
broken, 229
logic
in tests, 29, 223, 256
logs, 185
M
maintainability of tests, 209, 219-235
design principles, 223, 240
refactoring, 46, 240
test dependencies, 138
vs. complex tests, 223
vs. interactions testing, 69
vs. overspecified tests, 219
vs. PowerMock, 157
with TDD, 43
Make It Easy, 214
manual testing, 270
matchers, 109, 110-112
advantages, 112, 112
FEST (see FEST)
Hamcrest (see Hamcrest)
one line assertion, 149
reusability, 112
with Mockito, 113
writing custom, 110-112
Maven, 12, 257, 275
running tests, 280
test reports, 174
tests classpath, 282
using listeners and reporters, 281
methods
naming (see naming)
mock
definition, 77
example, 77, 283
forgiving, 285
nice, 67, 285
returning mock, 229
strict, 68, 285
vs. test spy, 283
mock object (see mock)
Mockito, 10
annotations, 202-204
295
Index
arguments to DOCs, 163
BDD support, 199
creating test doubles, 66-68, 200-204
Hamcrest matchers, 114
introduction, 65
number of invocations, 87
predefined matchers, 113
setting expectations, 68-69
stubbing
default values, 67
one-liners, 201
void methods, 109
verification, 69-71
Mockito API
@InjectMocks, 203
@Mock, 202
any(), 113
argThat(), 114
ArgumentCaptor, 166
contains(), 114
doReturn(), 161
endsWith(), 114
eq(), 113
getMock(), 201
initMocks(), 202
inOrder(), 231
is(), 113
matches(), 114
mock(), 66
MockitoAnnotations, 202
never(), 85, 88
refEq(), 113
same(), 113
spy(), 161
startsWith(), 114
stub(), 76
then Throw(), 68
thenReturn(), 68
times(), 87
verify(), 69
verifyNoMoreInteractions(), 231
verifyZeroInteractions(), 231
when(), 68, 199
That(), 114
mutant, 249
mutation testing, 248-253
N
naming, 192
O
Object-Oriented system, 2, 15, 224
overspecified tests, 229-233
issues, 226
nice mocks, 285
object-oriented approach, 225-227
test dependencies, 143
test fixture, 207
testing implementation, 219-223
P
parameters, 100-103, 197, 257
boundary values, 101
capturing, 163-168
expected, 100
from Excel file, 128
indirect, 103
null, 75
random, 134-137
relaxed verification, 113, 231
strange values, 101
verification, 71-71
parametrized tests, 25-26 (see data providers)
partial mocking, 160-162
PIT Mutation Testing, 11, 249-252
PMD, 239, 241
PowerMock, 11, 122
drawbacks, 157
java.util.Calendar, 122
new operator, 156-157
private methods, 153
private methods
in tests, 209, 256, 265
vs. matchers, 112
testing, 8, 150-154
access modifiers, 153
PowerMock, 153
reflection, 152
procedural code, 224-227
avoid, 228
project structure, 19
296
Index
packages, 190
Q
Quickcheck, 134
R
readable code
assertions, 23
collections testing, 126
common structure, 265
expected exceptions, 108
fluent interface, 194
focused tests, 263
irrelevant data, 262
meaningful names, 31, 194, 255, 260
Mockito syntax, 68
parameters, 261
refactoring, 258-266
self-contained test methods, 198, 265
using matchers, 110, 112, 114
vs. inheritance, 256
vs. set-up methods, 207
with Mockito annotations, 203
red-green-refactor (see TDD)
redesign, 120, 157
refactoring
done wrong, 47
example, 84
TDD rhythm, 46
test code, 47, 52, 240, 258-266
use in tests, 159, 160
vs. test doubles, 96
reports (see test reports)
S
saboteur, 68, 76 (see test spy)
set-up methods, 31, 47
pros & cons, 206-207
readability, 207
setter (see accessor method)
simplest thing that works, 46, 53, 56, 82
Single Responsibility Principle (see SRP principle)
spy (see test spy)
SRP principle, 46, 240
one reason to fail, 231
violation, 94, 139, 164, 230
state testing, 15-17, 19-36, 96
vs. interactions testing, 16-17, 233
static analysis tools, 241
static methods testing, 154-163
TDD, 40-62
benefits, 48, 228, 233
case against, 59
choosing next test, 44, 83
collections testing, 123
end-to-end tests, 48
example, 49-58, 79-89
how to start, 58
integration tests, 48
introduction, 40, 41
rhythm, 42-48, 60
test passes instantly, 57, 61
vs. legacy code, 60
when updating code, 232
with test doubles, 79-89
tear-down method, 35
Tell Dont Ask principle, 223, 229, 232
test code quality, 239-267
size heuristics, 254
test dependencies, 90, 138-147, 256
end-to-end tests, 138
fail fast, 140
hidden, 142
integration tests, 138
test documentation, 47, 196-197, 257
test doubles
benefits, 95
creation, 66
dummy (see dummy)
example, 77
expectations, 68
interactions, 72
introduction, 65
mock (see mock)
not using, 90-95, 227
test spy (see test spy)
test stub (see test stub)
types, 72
297
Index
variables naming, 195
verification, 69
unnecessary, 230
Test Driven Design (see TDD)
Test Driven Development (see TDD)
test fixture, 31-34, 204-207
complex objects, 207-214
examples, 32
in every test method, 32
set-up methods, 33, 206
TestNG annotations, 33, 204
test listeners, 179-182
example, 180, 182
with Gradle, 279
with Maven, 281
test reporters
with Gradle, 279
with Maven, 281
test reports, 186
code coverage, 243
custom, 177-179
example, 177
mutation testing, 251
TestNG default reports, 174
test result
error, 22
failed, 22
passed, 22
skipped, 22
test smell (see anti-pattern)
test spy
definition, 77
example, 77, 283
vs. mock, 283
test stub
definition, 76
example, 76
test-first (see TDD)
test-last (see code-first)
testing
collections, 122
thread safe (see concurrency)
time-dependent code, 119-122, 258
testing goal
better design, 7, 150, 155
verification, 7, 150, 155
TestNG, 10
assertions (see assertions)
basics, 21-22
U
unit tests
benefits, 13
definition, 13
examples, 6
interactions, 14
introduction, 4
phases, 34
term misuse, 13
test fixture examples, 32
Unitils, 11
collections testing, 125-125
V
variables
naming (see naming)
298
Index
Y
YAGNI principle, 82
You Aint Gonna Need It (see YAGNI principle)
299
Thank You!
Thank you for buying and reading this book! I really hope you have enjoyed it and taken a lot from it.
In case of questions, comments, or mistakes spotted, please feel free to contact me by posting to
[email protected].
Remember to visit http://practicalunittesting.com for source code and some additional materials.
Best Regards,
Tomek Kaczanowski
ccc