
- •Practical Unit Testing with JUnit and Mockito
- •Table of Contents
- •About the Author
- •Acknowledgments
- •Preface
- •Preface - JUnit
- •Part I. Developers' Tests
- •Chapter 1. On Tests and Tools
- •1.1. An Object-Oriented System
- •1.2. Types of Developers' Tests
- •1.2.1. Unit Tests
- •1.2.2. Integration Tests
- •1.2.3. End-to-End Tests
- •1.2.4. Examples
- •1.2.5. Conclusions
- •1.3. Verification and Design
- •1.5. Tools Introduction
- •Chapter 2. Unit Tests
- •2.1. What is a Unit Test?
- •2.2. Interactions in Unit Tests
- •2.2.1. State vs. Interaction Testing
- •2.2.2. Why Worry about Indirect Interactions?
- •Part II. Writing Unit Tests
- •3.2. Class To Test
- •3.3. Your First JUnit Test
- •3.3.1. Test Results
- •3.4. JUnit Assertions
- •3.5. Failing Test
- •3.6. Parameterized Tests
- •3.6.1. The Problem
- •3.6.2. The Solution
- •3.6.3. Conclusions
- •3.7. Checking Expected Exceptions
- •3.8. Test Fixture Setting
- •3.8.1. Test Fixture Examples
- •3.8.2. Test Fixture in Every Test Method
- •3.8.3. JUnit Execution Model
- •3.8.4. Annotations for Test Fixture Creation
- •3.9. Phases of a Unit Test
- •3.10. Conclusions
- •3.11. Exercises
- •3.11.1. JUnit Run
- •3.11.2. String Reverse
- •3.11.3. HashMap
- •3.11.4. Fahrenheits to Celcius with Parameterized Tests
- •3.11.5. Master Your IDE
- •Templates
- •Quick Navigation
- •Chapter 4. Test Driven Development
- •4.1. When to Write Tests?
- •4.1.1. Test Last (AKA Code First) Development
- •4.1.2. Test First Development
- •4.1.3. Always after a Bug is Found
- •4.2. TDD Rhythm
- •4.2.1. RED - Write a Test that Fails
- •How To Choose the Next Test To Write
- •Readable Assertion Message
- •4.2.2. GREEN - Write the Simplest Thing that Works
- •4.2.3. REFACTOR - Improve the Code
- •Refactoring the Tests
- •Adding Javadocs
- •4.2.4. Here We Go Again
- •4.3. Benefits
- •4.4. TDD is Not Only about Unit Tests
- •4.5. Test First Example
- •4.5.1. The Problem
- •4.5.2. RED - Write a Failing Test
- •4.5.3. GREEN - Fix the Code
- •4.5.4. REFACTOR - Even If Only a Little Bit
- •4.5.5. First Cycle Finished
- •‘The Simplest Thing that Works’ Revisited
- •4.5.6. More Test Cases
- •But is It Comparable?
- •Comparison Tests
- •4.6. Conclusions and Comments
- •4.7. How to Start Coding TDD
- •4.8. When not To Use Test-First?
- •4.9. Should I Follow It Blindly?
- •4.9.1. Write Good Assertion Messages from the Beginning
- •4.9.2. If the Test Passes "By Default"
- •4.10. Exercises
- •4.10.1. Password Validator
- •4.10.2. Regex
- •4.10.3. Booking System
- •Chapter 5. Mocks, Stubs, Test Spies
- •5.1. Introducing Mockito
- •5.1.1. Creating Test Doubles
- •5.1.2. Expectations
- •5.1.3. Verification
- •5.1.4. Conclusions
- •5.2. Types of Test Double
- •5.2.1. Code To Be Tested with Test Doubles
- •5.2.2. The Dummy Object
- •5.2.3. Test Stub
- •5.2.4. Test Spy
- •5.2.5. Mock
- •5.3. Putting it All Together
- •5.4. Example: TDD with Test Doubles
- •5.4.2. The Second Test: Send a Message to Multiple Subscribers
- •Refactoring
- •5.4.3. The Third Test: Send Messages to Subscribers Only
- •5.4.4. The Fourth Test: Subscribe More Than Once
- •Mockito: How Many Times?
- •5.4.5. The Fifth Test: Remove a Subscriber
- •5.4.6. TDD and Test Doubles - Conclusions
- •More Test Code than Production Code
- •The Interface is What Really Matters
- •Interactions Can Be Tested
- •Some Test Doubles are More Useful than Others
- •5.5. Always Use Test Doubles… or Maybe Not?
- •5.5.1. No Test Doubles
- •5.5.2. Using Test Doubles
- •No Winner So Far
- •5.5.3. A More Complicated Example
- •5.5.4. Use Test Doubles or Not? - Conclusion
- •5.6. Conclusions (with a Warning)
- •5.7. Exercises
- •5.7.1. User Service Tested
- •5.7.2. Race Results Enhanced
- •5.7.3. Booking System Revisited
- •5.7.4. Read, Read, Read!
- •Part III. Hints and Discussions
- •Chapter 6. Things You Should Know
- •6.1. What Values To Check?
- •6.1.1. Expected Values
- •6.1.2. Boundary Values
- •6.1.3. Strange Values
- •6.1.4. Should You Always Care?
- •6.1.5. Not Only Input Parameters
- •6.2. How to Fail a Test?
- •6.3. How to Ignore a Test?
- •6.4. More about Expected Exceptions
- •6.4.1. The Expected Exception Message
- •6.4.2. Catch-Exception Library
- •6.4.3. Testing Exceptions And Interactions
- •6.4.4. Conclusions
- •6.5. Stubbing Void Methods
- •6.6. Matchers
- •6.6.1. JUnit Support for Matcher Libraries
- •6.6.2. Comparing Matcher with "Standard" Assertions
- •6.6.3. Custom Matchers
- •6.6.4. Advantages of Matchers
- •6.7. Mockito Matchers
- •6.7.1. Hamcrest Matchers Integration
- •6.7.2. Matchers Warning
- •6.8. Rules
- •6.8.1. Using Rules
- •6.8.2. Writing Custom Rules
- •6.9. Unit Testing Asynchronous Code
- •6.9.1. Waiting for the Asynchronous Task to Finish
- •6.9.2. Making Asynchronous Synchronous
- •6.9.3. Conclusions
- •6.10. Testing Thread Safe
- •6.10.1. ID Generator: Requirements
- •6.10.2. ID Generator: First Implementation
- •6.10.3. ID Generator: Second Implementation
- •6.10.4. Conclusions
- •6.11. Time is not on Your Side
- •6.11.1. Test Every Date (Within Reason)
- •6.11.2. Conclusions
- •6.12. Testing Collections
- •6.12.1. The TDD Approach - Step by Step
- •6.12.2. Using External Assertions
- •Unitils
- •Testing Collections Using Matchers
- •6.12.3. Custom Solution
- •6.12.4. Conclusions
- •6.13. Reading Test Data From Files
- •6.13.1. CSV Files
- •6.13.2. Excel Files
- •6.14. Conclusions
- •6.15. Exercises
- •6.15.1. Design Test Cases: State Testing
- •6.15.2. Design Test Cases: Interactions Testing
- •6.15.3. Test Collections
- •6.15.4. Time Testing
- •6.15.5. Redesign of the TimeProvider class
- •6.15.6. Write a Custom Matcher
- •6.15.7. Preserve System Properties During Tests
- •6.15.8. Enhance the RetryTestRule
- •6.15.9. Make an ID Generator Bulletproof
- •Chapter 7. Points of Controversy
- •7.1. Access Modifiers
- •7.2. Random Values in Tests
- •7.2.1. Random Object Properties
- •7.2.2. Generating Multiple Test Cases
- •7.2.3. Conclusions
- •7.3. Is Set-up the Right Thing for You?
- •7.4. How Many Assertions per Test Method?
- •7.4.1. Code Example
- •7.4.2. Pros and Cons
- •7.4.3. Conclusions
- •7.5. Private Methods Testing
- •7.5.1. Verification vs. Design - Revisited
- •7.5.2. Options We Have
- •7.5.3. Private Methods Testing - Techniques
- •Reflection
- •Access Modifiers
- •7.5.4. Conclusions
- •7.6. New Operator
- •7.6.1. PowerMock to the Rescue
- •7.6.2. Redesign and Inject
- •7.6.3. Refactor and Subclass
- •7.6.4. Partial Mocking
- •7.6.5. Conclusions
- •7.7. Capturing Arguments to Collaborators
- •7.8. Conclusions
- •7.9. Exercises
- •7.9.1. Testing Legacy Code
- •Part IV. Listen and Organize
- •Chapter 8. Getting Feedback
- •8.1. IDE Feedback
- •8.1.1. Eclipse Test Reports
- •8.1.2. IntelliJ IDEA Test Reports
- •8.1.3. Conclusion
- •8.2. JUnit Default Reports
- •8.3. Writing Custom Listeners
- •8.4. Readable Assertion Messages
- •8.4.1. Add a Custom Assertion Message
- •8.4.2. Implement the toString() Method
- •8.4.3. Use the Right Assertion Method
- •8.5. Logging in Tests
- •8.6. Debugging Tests
- •8.7. Notifying The Team
- •8.8. Conclusions
- •8.9. Exercises
- •8.9.1. Study Test Output
- •8.9.2. Enhance the Custom Rule
- •8.9.3. Custom Test Listener
- •8.9.4. Debugging Session
- •Chapter 9. Organization Of Tests
- •9.1. Package for Test Classes
- •9.2. Name Your Tests Consistently
- •9.2.1. Test Class Names
- •Splitting Up Long Test Classes
- •Test Class Per Feature
- •9.2.2. Test Method Names
- •9.2.3. Naming of Test-Double Variables
- •9.3. Comments in Tests
- •9.4. BDD: ‘Given’, ‘When’, ‘Then’
- •9.4.1. Testing BDD-Style
- •9.4.2. Mockito BDD-Style
- •9.5. Reducing Boilerplate Code
- •9.5.1. One-Liner Stubs
- •9.5.2. Mockito Annotations
- •9.6. Creating Complex Objects
- •9.6.1. Mummy Knows Best
- •9.6.2. Test Data Builder
- •9.6.3. Conclusions
- •9.7. Conclusions
- •9.8. Exercises
- •9.8.1. Test Fixture Setting
- •9.8.2. Test Data Builder
- •Part V. Make Them Better
- •Chapter 10. Maintainable Tests
- •10.1. Test Behaviour, not Methods
- •10.2. Complexity Leads to Bugs
- •10.3. Follow the Rules or Suffer
- •10.3.1. Real Life is Object-Oriented
- •10.3.2. The Non-Object-Oriented Approach
- •Do We Need Mocks?
- •10.3.3. The Object-Oriented Approach
- •10.3.4. How To Deal with Procedural Code?
- •10.3.5. Conclusions
- •10.4. Rewriting Tests when the Code Changes
- •10.4.1. Avoid Overspecified Tests
- •10.4.2. Are You Really Coding Test-First?
- •10.4.3. Conclusions
- •10.5. Things Too Simple To Break
- •10.6. Conclusions
- •10.7. Exercises
- •10.7.1. A Car is a Sports Car if …
- •10.7.2. Stack Test
- •Chapter 11. Test Quality
- •11.1. An Overview
- •11.2. Static Analysis Tools
- •11.3. Code Coverage
- •11.3.1. Line and Branch Coverage
- •11.3.2. Code Coverage Reports
- •11.3.3. The Devil is in the Details
- •11.3.4. How Much Code Coverage is Good Enough?
- •11.3.5. Conclusion
- •11.4. Mutation Testing
- •11.4.1. How does it Work?
- •11.4.2. Working with PIT
- •11.4.3. Conclusions
- •11.5. Code Reviews
- •11.5.1. A Three-Minute Test Code Review
- •Size Heuristics
- •But do They Run?
- •Check Code Coverage
- •Conclusions
- •11.5.2. Things to Look For
- •Easy to Understand
- •Documented
- •Are All the Important Scenarios Verified?
- •Run Them
- •Date Testing
- •11.5.3. Conclusions
- •11.6. Refactor Your Tests
- •11.6.1. Use Meaningful Names - Everywhere
- •11.6.2. Make It Understandable at a Glance
- •11.6.3. Make Irrelevant Data Clearly Visible
- •11.6.4. Do not Test Many Things at Once
- •11.6.5. Change Order of Methods
- •11.7. Conclusions
- •11.8. Exercises
- •11.8.1. Clean this Mess
- •Appendix A. Automated Tests
- •A.1. Wasting Your Time by not Writing Tests
- •A.1.1. And what about Human Testers?
- •A.1.2. One More Benefit: A Documentation that is Always Up-To-Date
- •A.2. When and Where Should Tests Run?
- •Appendix B. Running Unit Tests
- •B.1. Running Tests with Eclipse
- •B.1.1. Debugging Tests with Eclipse
- •B.2. Running Tests with IntelliJ IDEA
- •B.2.1. Debugging Tests with IntelliJ IDEA
- •B.3. Running Tests with Gradle
- •B.3.1. Using JUnit Listeners with Gradle
- •B.3.2. Adding JARs to Gradle’s Tests Classpath
- •B.4. Running Tests with Maven
- •B.4.1. Using JUnit Listeners and Reporters with Maven
- •B.4.2. Adding JARs to Maven’s Tests Classpath
- •Appendix C. Test Spy vs. Mock
- •C.1. Different Flow - and Who Asserts?
- •C.2. Stop with the First Error
- •C.3. Stubbing
- •C.4. Forgiveness
- •C.5. Different Threads or Containers
- •C.6. Conclusions
- •Appendix D. Where Should I Go Now?
- •Bibliography
- •Glossary
- •Index
- •Thank You!

Chapter 7. Points of Controversy
7.6. New Operator
A seam is a place where you can alter behavior in your program without editing in that place.
— Michael Feathers Working Effectively With Legacy Code (2004)
When introducing test doubles (in Chapter 5, Mocks, Stubs, Test Spies), we assumed that the collaborators of the SUT could be replaced easily. This is the case if they are "injected" into the SUT - as constructor parameters, method parameters or using setters. However, this is not always the case. This section explains what can be done if there is no straightforward way of replacing the SUT’s collaborators.
Listing 7.13 presents some very simple code. The myMethod() method of the MySut class creates another object (of the MyCollaborator class) using the new operator. Then it uses this newly created object (calls its methods, uses values it returns, etc.).
Listing 7.13. 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
}
}
The code in Listing 7.13 is perfectly valid Java code and, frankly, not complicated either. However, testing interactions between the SUT and its collaborator requires some additional effort. A test skeleton for such a method would look as shown below:
Listing 7.14. Testing new - a test skeleton
public class MySutTest {
@Test
public void testMyMethod() { MySut sut = new MySut();
MyCollaborator collaborator = mock(MyCollaborator.class);
//make sut use collaborator
//set expectations regarding collaborator's behaviour
//execute sut's method(s)
//verify results and/or collaborator's behaviour
}
}
Creation of the SUT.
Creation of a test double for the SUT’s collaborator. "Make sut use collaborator" - but how?!
When writing a test for the MySut class, we very quickly encounter a problem. There is no direct way to force sut to use a test double of the MyCollaborator class. This means that we cannot easily control the SUT’s environment. One option we have is to forget about testing in isolation, and test both classes (MySut and MyCollaborator) together. While this might work out pretty well in the short run (see the discussion in Section 5.5), it makes it hard to test all of the scenarios we should test. We don’t need to relive the whole debate about this: isolation in tests is usually worth fighting for, so let us fight for it!
160

Chapter 7. Points of Controversy
Even though myMethod() uses the new operator to create its collaborator, the discussion in this section also covers other similar situations. In particular, if myMethod() had used
a factory pattern (e.g. MyCollaborator collaborator = MyFactory.getCollaborator(…)),
instead of the new operator, or had used a lookup service (e.g. MyCollaborator collaborator = LookupService.findCollaborator(…)), that would have caused exactly the same problem when testing. The solutions discussed in the following sections would also apply to these similar scenarios.
Now that we understand the problem, let us discuss possible solutions to it. Each of them has its own pros and cons, which will be discussed in the sections below. But before we take a closer look at them, let us get clear about exactly what kind of a dilemma we are faced with here.
As was stated in Section 1.3, tools for testing can be divided into two types. Some of them only deal with verification, while others are more concerned with design. Mockito belongs to the second group: it works perfectly with well-written, loosely coupled code, but "refuses" to test code that is tightly-coupled. The problem we are facing right now – the use of either the new operator or static methods - is precisely a representation of what happens when the code is not loosely coupled. The ties between objects (in this case between sut and collaborator) are so tight that it is hard to loosen them for testing purposes.
Having read this, one might well expect the solutions called for to come from using both types of tool. And this is exactly the case. Either we can use a tool that allows us to test tightly coupled code, or we will find it necessary to introduce some changes to the original code (hopefully making it better), and then use a tool from the second group.
7.6.1. PowerMock to the Rescue
We shall start with a tool which can simply ignore the nuisance that is the new operator, and create a test double, as if that were no issue at all. Such "magic" is possible with PowerMock.
Listing 7.15 presents a test class which uses PowerMock. It does not differ substantially from what we have encountered so far, but uses some annotations and classes which we have not yet come across.
PowerMock acts as a kind of wrapper around different mocking frameworks. It enhances their functionality with some new features. I will not go deeply into the details of the PowerMock syntax, nor will I discuss all of its capabilities. Please refer to PowerMock’s documentation for the full list of features, and detailed instructions on how to use it with Mockito and JUnit.
161

Chapter 7. Points of Controversy
Listing 7.15. Using PowerMock to test the new operator
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner;
@PrepareForTest(MySut.class) @RunWith(PowerMockRunner.class) public class MySutTest {
@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(...)
}
}
Required imports.
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 on.
A special runner is used so PowerMock can be used within JUnit tests.
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 PowerMock’s 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.
And that is it. Except for some annotations required in order to use PowerMock and JUnit together, there is not much new here: only that in some places the PowerMockito class is used instead of the Mockito class. Apart from this, the code looks very similar to what we have come across so far.
Let us conclude by summing up what this example has showed us:
•there are tools (i.e. PowerMock) capable of dealing with the new operator, static method calls, and other language constructs, which are commonly recognized as being "untestable",
•it is possible to test classes like the MySut class without changing (refactoring or redesigning) them at all,
•PowerMock works nicely with JUnit and Mockito,
•tests written with PowerMock do not differ much from what we have become used to.
After seeing what PowerMock can do for us, we should answer one question, which is surely shouting in our heads: "Why bother with anything else if I can do it so easily using PowerMock?!"
There is a serious reason for avoiding using such tools. It is all about the quality of your code - in particular, about its maintainability. By using PowerMock as shown in Listing 7.15, you reproduce in
162

Chapter 7. Points of Controversy
your test code the tight-coupling which exists in the production code. Now, every time you change your production code, your tests will fail. By including implementation details in your tests (as PowerMock requires you to do) you have created an additional force which will make it harder to introduce changes to your production code. This is not good.
Additionally, PowerMock lets you get away with suboptimal design. For example, a class can have way too much responsibility and still be capable of being tested with PowerMock. Testing it with other tools would be very cumbersome, but with PowerMock you will not feel the pain. In short, using PowerMock deprives you of valuable feedback about the quality of your code, which other tools will give you.
However, there are situations where having PowerMock in your toolbox is a real blessing. That is why I have decided to present this tool, even though I myself do not use it on a daily basis.
7.6.2. Redesign and Inject
Now we will be going in a direction quite opposite to that which we went in with PowerMock: we shall be working on the production code, to make it more testable. After this goal has been accomplished, we will be able to use a common Mockito approach, without using any reflection or class loading tricks.
Basically, there are two ways in which a collaborator object can be replaced easily with a test double:
•create a new field in a MySut class of the MyCollaborator type, and
•either pass an object of the MyCollaborator class as the constructor’s argument, or via a setter method,
•or redesign myMethod() so it takes an object of the MyCollaborator class as one of it arguments.
No matter which option we choose, writing test code will then be a piece of cake. Listing 7.16 shows a refactored MySut class (with a constructor-injected collaborator), and Listing 7.17 shows a test written for this class.
Listing 7.16. MySut class with constructor-injected collaborator
public class MySut {
private final MyCollaborator collab;
public MySut(MyCollaborator collab) { this.collab = collab;
}
public void myMethod() {
// some behaviour worth testing here which uses collaborator
}
}
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.
163