Practical Unit Testing with TestNG and Mockito
Table of Contents
About the Author
Acknowledgments
Preface
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.4. But Should Developers Test Their Own Code?!
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
Chapter 3. Unit Tests with no Collaborators
3.1. Project Structure and Naming Conventions
3.2. Class To Test
3.3. Your First TestNG Test
3.3.1. Test Results
3.4. TestNG Assertions
3.5. Failing Test
3.6. Parametrized Tests
3.6.1. The Problem
3.6.2. The Solution
3.6.3. Reusing Data Providers
3.6.4. Dynamic Data Providers
3.6.5. 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. Annotations for Test Fixture Creation
3.9. Phases of a Unit Test
3.10. Conclusions
3.11. Exercises
3.11.1. TestNG Run
3.11.2. String Reverse
3.11.3. HashMap
3.11.4. Fahrenheits to Celcius with Data Providers
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.1. First Test: Single Subscriber Receives Message
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
Test Dependencies are There, whether You Like It or Not
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. More about Expected Exceptions
6.3.1. The Expected Exception Message
6.3.2. When Having a Common Pattern is not Enough
6.3.3. catch-exception Library
6.3.4. Conclusions
6.4. Stubbing Void Methods
6.5. Matchers
6.6. Mockito Matchers
6.6.1. Hamcrest Matchers Integration
6.6.2. Matchers Warning
6.7. Testing Thread Safe
6.7.1. ID Generator: Requirements
6.7.2. ID Generator: First Implementation
6.7.3. ID Generator: Second Implementation
6.7.4. Conclusions
6.8. Time is not on Your Side
6.8.1. Test Every Date (Within Reason)
6.8.2. Conclusions
6.9. Testing Collections
6.9.1. The TDD Approach - Step by Step
6.9.2. TestNG Assertions for Collections Verification
6.9.3. Using External Assertions
Unitils
Testing Collections Using Matchers
6.9.4. Custom Solution
6.9.5. Conclusions
6.10. Reading Data From Excel Files
6.11. Conclusions
6.12. Exercises
6.12.1. Design Test Cases: State Testing
6.12.2. Design Test Cases: Interactions Testing
6.12.3. Test Collections
6.12.4. Time Testing
6.12.5. Write a Custom Matcher
6.12.6. Make an ID Generator Bulletproof
Chapter 7. Points of Controversy
7.1. Random Values in Tests
7.1.1. Random Object Properties
7.1.2. Generating Multiple Test Cases
7.1.3. Conclusions
7.2. Test Dependencies
7.2.1. Test Dependencies and the DRY Principle
7.2.2. Fail Fast
7.2.3. Make It Explicit
7.2.4. Remove Unnecessary Test Dependencies
7.2.5. Conclusions
7.3. How Many Assertions per Test Method?
7.3.1. Code Example
7.3.2. Pros and Cons
7.3.3. Conclusions
7.4. Private Methods Testing
7.4.1. Verification vs. Design - Revisited
7.4.2. Options We Have
7.4.3. Private Methods Testing - Techniques
Reflection
Access Modifiers
7.4.4. Conclusions
7.5. New Operator
7.5.1. PowerMock to the Rescue
7.5.2. Redesign and Inject
7.5.3. Refactor and Subclass
7.5.4. Partial Mocking
7.5.5. Conclusions
7.6. Capturing Arguments to Collaborators
7.6.1. Capturing Arguments - Creating Identical Objects
7.6.2. Capturing Arguments - Using Mockito’s Features
7.7. Conclusions
7.8. Exercises
7.8.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. The Default Reports of TestNG
8.2.1. Adding More Information to the HTML Reports
8.3. Writing Custom Reporters and Listeners
8.3.1. Writing Your Own Test Reporter
8.3.2. Writing Your Own Test Listeners
DotTestListener
SkippedTestListener
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. Read Test Data from a CSV File
8.9.3. Custom Test Listener
8.9.4. Debugging Session
Chapter 9. Organization Of Tests
9.1. Package for Test Classes
9.2. @Test Annotations
9.3. Name Your Tests Consistently
9.3.1. Test Class Names
Splitting Up Long Test Classes
Test Class Per Feature
9.3.2. Test Method Names
9.3.3. Naming of Test-Double Variables
9.4. Comments in Tests
9.5. BDD: ‘Given’, ‘When’, ‘Then’
9.5.1. Testing BDD-Style
9.5.2. Mockito BDD-Style
9.6. Reducing Boilerplate Code
9.6.1. One-Liner Stubs
9.6.2. Mockito Annotations
9.7. More on Test Fixture Setting
9.7.1. TestNG BeforeXYZ Annotations
9.7.2. Is Set-up the Right Thing for You?
9.8. Creating Complex Objects
9.8.1. Mummy Knows Best
9.8.2. Test Data Builder
9.8.3. Conclusions
9.9. Conclusions
9.10. Exercises
9.10.1. Test Fixture Setting
9.10.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.6.6. Do not Go Too Far
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 TestNG Listeners and Reporters with Gradle
B.3.2. Adding JARs to Gradle’s Tests Classpath
B.4. Running Tests with Maven
B.4.1. Using TestNG 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!