M A N N I N G THIRD EDITION Catalin Tudose˘ ˘
JUnit5 Old test Vintage New test Jupiter IDEs/Build tools Platform Another test Third party
JUnit in Action THIRD EDITION CĂTĂLIN TUDOSE M A N N I N G SHELTER ISLAND
For online information and ordering of this and other Manning books, please visit www.manning.com. The publisher offers discounts on this book when ordered in quantity. For more information, please contact Special Sales Department Manning Publications Co. 20 Baldwin Road PO Box 761 Shelter Island, NY 11964 Email: orders@manning.com ©2020 by Manning Publications Co. All rights reserved. No part of this publication may be reproduced, stored in a retrieval system, or transmitted, in any form or by means electronic, mechanical, photocopying, or otherwise, without prior written permission of the publisher. Many of the designations used by manufacturers and sellers to distinguish their products are claimed as trademarks. Where those designations appear in the book, and Manning Publications was aware of a trademark claim, the designations have been printed in initial caps or all caps. Recognizing the importance of preserving what has been written, it is Manning’s policy to have the books we publish printed on acid-free paper, and we exert our best efforts to that end. Recognizing also our responsibility to conserve the resources of our planet, Manning books are printed on paper that is at least 15 percent recycled and processed without the use of elemental chlorine. Manning Publications Co. Development editor: Katie Sposato Johnson 20 Baldwin Road Technical development editor: John Guthrie PO Box 761 Review editor: Mihaela Batinic Shelter Island, NY 11964 Production editor: Deirdre S. Hiam Copy editor: Tiffany Taylor Proofreader: Katie Tennant Technical proofreader: David Cabrero Typesetter and cover designer: Marija Tudor ISBN 9781617297045 Printed in the United States of America
This book is dedicated to all those people who made it possible: family, friends, colleagues, professors, students. Cătălin Tudose
contents preface xiii acknowledgments xv about this book xvi about the author xix about the cover illustration xx PART 1 JUNIT ............................................................. 1 1 JUnit jump-start 3 1.1 Proving that a program works 4 1.2 Starting from scratch 6 Understanding unit testing frameworks 8 ■ Adding unit tests 9 1.3 Setting up JUnit 9 1.4 Testing with JUnit 12 2 Exploring core JUnit 15 2.1 Core annotations 16 The @DisplayName annotation 19 ■ The @Disabled annotation 20 2.2 Nested tests 21 2.3 Tagged tests 23 2.4 Assertions 25v
CONTENTSvi2.5 Assumptions 29 2.6 Dependency injection in JUnit 5 31 TestInfoParameterResolver 31 ■ TestReporterParameterResolver 32 RepetitionInfoParameterResolver 33 2.7 Repeated tests 33 2.8 Parameterized tests 35 2.9 Dynamic tests 38 2.10 Using Hamcrest matchers 40 3 JUnit architecture 47 3.1 The concept and importance of software architecture 48 Story 1: The telephone directories 48 ■ Story 2: The sneakers manufacturer 49 3.2 The JUnit 4 architecture 49 JUnit 4 modularity 50 ■ JUnit 4 runners 50 ■ JUnit 4 rules 52 ■ Shortcomings of the JUnit 4 architecture 58 3.3 The JUnit 5 architecture 58 JUnit 5 modularity 58 ■ JUnit Platform 59 ■ JUnit Jupiter 60 JUnit Vintage 60 ■ The big picture of the JUnit 5 architecture 60 4 Migrating from JUnit 4 to JUnit 5 63 4.1 Migration steps between JUnit 4 and JUnit 5 64 4.2 Needed dependencies 65 4.3 Annotations, classes, and methods 67 Equivalent annotations, classes, and methods 67 ■ Categories vs. tags 71 ■ Migrating Hamcrest matcher functionality 77 Rules vs. the extension model 78 ■ Custom rules 82 5 Software testing principles 87 5.1 The need for unit tests 88 Allowing greater test coverage 88 ■ Increasing team productivity 88 ■ Detecting regressions and limiting debugging 88 ■ Refactoring with confidence 89 ■ Improving implementation 90 ■ Documenting expected behavior 90 Enabling code coverage and other metrics 91 5.2 Test types 92 Unit testing 92 ■ Integration software testing 93 ■ System software testing 93 ■ Acceptance software testing 94
CONTENTS vii5.3 Black-box vs. white-box testing 94 Black-box testing 95 ■ White-box testing 95 ■ Pros and cons 96 PART 2 DIFFERENT TESTING STRATEGIES .................... 99 6 Test quality 101 6.1 Measuring test coverage 102 Introduction to test coverage 102 ■ Tools for measuring code coverage 103 6.2 Writing testable code 108 Understanding that public APIs are contracts 108 ■ Reducing dependencies 108 ■ Creating simple constructors 110 Following the Law of Demeter (Principle of Least Knowledge) 110 Avoiding hidden dependencies and global state 112 Favoring generic methods 113 ■ Favoring composition over inheritance 114 ■ Favoring polymorphism over conditionals 114 6.3 Test-driven development 116 Adapting the development cycle 116 ■ Doing the TDD two-step 117 6.4 Behavior-driven development 117 6.5 Mutation testing 118 6.6 Testing in the development cycle 119 7 Coarse-grained testing with stubs 123 7.1 Introducing stubs 124 7.2 Stubbing an HTTP connection 125 Choosing a stubbing solution 128 ■ Using Jetty as an embedded server 128 7.3 Stubbing the web server resources 130 Setting up the first stub test 130 ■ Reviewing the first stub test 133 7.4 Stubbing the connection 134 Producing a custom URL protocol handler 134 ■ Creating a JDK HttpURLConnection stub 135 ■ Running the test 136 8 Testing with mock objects 138 8.1 Introducing mock objects 139 8.2 Unit testing with mock objects 139
CONTENTSviii8.3 Refactoring with mock objects 143 Refactoring example 144 ■ Refactoring considerations 145 8.4 Mocking an HTTP connection 147 Defining the mock objects 147 ■ Testing a sample method 148 Try #1: Easy refactoring technique 149 ■ Try #2: Refactoring by using a class factory 151 8.5 Using mocks as Trojan horses 154 8.6 Introducing mock frameworks 156 Using EasyMock 157 ■ Using JMock 162 ■ Using Mockito 166 9 In-container testing 170 9.1 Limitations of standard unit testing 171 9.2 The mock-objects solution 172 9.3 The step to in-container testing 174 Implementation strategies 174 ■ In-container testing frameworks 175 9.4 Comparing stubs, mock objects, and in-container testing 175 Stubs evaluation 175 ■ Mock-objects evaluation 176 In-container testing evaluation 177 9.5 Testing with Arquillian 178 PART 3 WORKING WITH JUNIT 5 AND OTHER TOOLS 187 10 Running JUnit tests from Maven 3 189 10.1 Setting up a Maven project 190 10.2 Using the Maven plugins 193 Maven compiler plugin 194 ■ Maven Surefire plugin 195 Generating HTML JUnit reports with Maven 197 10.3 Putting it all together 198 10.4 Maven challenges 203 11 Running JUnit tests from Gradle 6 205 11.1 Introducing Gradle 206 11.2 Setting up a Gradle project 207 11.3 Using Gradle plugins 212
CONTENTS ix11.4 Creating a Gradle project from scratch and testing it with JUnit 5 213 11.5 Comparing Gradle and Maven 218 12 JUnit 5 IDE support 219 12.1 Using JUnit 5 with IntelliJ IDEA 220 12.2 Using JUnit 5 with Eclipse 226 12.3 Using JUnit 5 with NetBeans 232 12.4 Comparing JUnit 5 usage in IntelliJ, Eclipse, and NetBeans 238 13 Continuous integration with JUnit 5 240 13.1 Continuous integration testing 241 13.2 Introducing Jenkins 243 13.3 Practicing CI on a team 246 13.4 Configuring Jenkins 251 13.5 Working on tasks in a CI environment 255 PART 4 WORKING WITH MODERN FRAMEWORKS AND JUNIT 5 ................................................ 261 14 JUnit 5 extension model 263 14.1 Introducing the JUnit 5 extension model 264 14.2 Creating a JUnit 5 extension 264 14.3 Writing JUnit 5 tests using the available extension points 268 Persisting passengers to a database 268 ■ Checking the uniqueness of passengers 277 15 Presentation-layer testing 281 15.1 Choosing a testing framework 282 15.2 Introducing HtmlUnit 282 A live example 282 15.3 Writing HtmlUnit tests 284 HTML assertions 284 ■ Testing for a specific web browser 285 Testing more than one web browser 285 ■ Creating standalone tests 286 ■ Testing forms 288 ■ Testing JavaScript 290
CONTENTSx15.4 Introducing Selenium 294 15.5 Writing Selenium tests 295 Testing for a specific web browser 297 ■ Testing navigation using a web browser 298 ■ Testing more than one web browser 299 Testing Google search and navigation using different web browsers 301 ■ Testing website authentication 303 15.6 HtmlUnit vs. Selenium 309 16 Testing Spring applications 311 16.1 Introducing the Spring Framework 311 16.2 Introducing dependency injection 312 16.3 Using and testing a Spring application 317 Creating the Spring context programmatically 317 ■ Using the Spring TestContext framework 321 16.4 Using SpringExtension for JUnit Jupiter 322 16.5 Adding a new feature and testing it with JUnit 5 325 17 Testing Spring Boot applications 333 17.1 Introducing Spring Boot 334 17.2 Creating a project with Spring Initializr 334 17.3 Moving the Spring application to Spring Boot 337 17.4 Implementing a test-specific configuration for Spring Boot 339 17.5 Adding and testing a new feature in the Spring Boot application 342 18 Testing a REST API 348 18.1 Introducing REST applications 349 18.2 Creating a RESTful API to manage one entity 350 18.3 Creating a RESTful API to manage two related entities 357 18.4 Testing the RESTful API 364 19 Testing database applications 369 19.1 The database unit testing impedance mismatch 370 Unit tests must exercise code in isolation 370 ■ Unit tests must be easy to write and run 370 ■ Unit tests must be fast to run 371
CONTENTS xi19.2 Testing a JDBC application 372 19.3 Testing a Spring JDBC application 381 19.4 Testing a Hibernate application 388 19.5 Testing a Spring Hibernate application 393 19.6 Comparing the approaches for testing database applications 400 PART 5 DEVELOPING APPLICATIONS WITH JUNIT 5 ... 403 20 Test-driven development with JUnit 5 405 20.1 TDD main concepts 406 20.2 The flight-management application 407 20.3 Preparing the flight-management application for TDD 412 20.4 Refactoring the flight-management application 416 20.5 Introducing new features using TDD 420 Adding a premium flight 420 ■ Adding a passenger only once 429 21 Behavior-driven development with JUnit 5 434 21.1 Introducing behavior-driven development 435 Introducing a new feature 435 ■ From requirements analysis to acceptance criteria 436 ■ BDD benefits and challenges 437 21.2 Working BDD style with Cucumber and JUnit 5 437 Introducing Cucumber 438 ■ Moving a TDD feature to Cucumber 439 ■ Adding a new feature with the help of Cucumber 447 21.3 Working BDD style with JBehave and JUnit 5 454 Introducing JBehave 455 ■ Moving a TDD feature to JBehave 455 ■ Adding a new feature with the help of JBehave 461 21.4 Comparing Cucumber and JBehave 469 22 Implementing a test pyramid strategy with JUnit 5 471 22.1 Software testing levels 472 22.2 Unit testing: Basic components working in isolation 473 22.3 Integration testing: Units combined into a group 483
CONTENTSxii22.4 System testing: Looking at the complete software 491 Testing with a mock external dependency 491 ■ Testing with a partially implemented external dependency 495 ■ Testing with the fully implemented external dependency 498 22.5 Acceptance testing: Compliance with business requirements 501 appendix A Maven 513 appendix B Gradle 520 appendix C IDEs 525 appendix D Jenkins 528 index 531
preface I am fortunate to have been in the IT industry for almost 25 years. I started program- ming in C++ and Delphi, and that is how I spent my student years and the first years of my career. I made the step from my mathematics background as a teenager to com- puter science and always kept both studies in mind. In 2000, my attention turned for the first time to the Java programming language, which was very young, but many peo- ple were predicting a great future for it. I was part of a team developing online games, using a particular technology: applets, which were extremely fashionable during those years. Our team spent some time developing and some more time testing, which was mainly done manually: we played together in the network and tried to discover the corner cases by ourselves. We hadn’t heard about JUnit or test-driven development, which were in the pioneering stages. After 2004, Java dominated about 90% of my work life. It was the dawn of a new era for me, and things like code refactoring, unit testing, and test-driven development became part of my normal professional life. Nowadays, I cannot imagine a project (even if it is a smaller one) without automated testing, and neither can Luxoft, the company I work for. My fellow developers talk about how they do automated testing in their current work, what the client expectations are, how they measure and increase code coverage, and how they analyze the quality of tests. Not only are unit testing and test-driven development at the heart of the conversation, but so also is behavior-driven development. We now cannot imagine shipping a product to fulfill market expecta- tions without solid tests: an actual pyramid of unit tests, integration tests, system tests, and acceptance tests. I was also fortunate to get in contact with Manning after having already developed three courses about automated testing for Pluralsight. I didn't have to start this book from scratch: the second edition was already a best seller. But it was written for 2010xiii
PREFACExivand JUnit 4, and 10 years look like centuries in the IT field! I made the big step to JUnit 5 and present-day hot technologies and working methodologies. Unit testing and JUnit have come a long way since their early days when I began working with them. The concept is simple, but careful consideration and planning are required when migrating from JUnit 4 to 5. The book effectively provides that information, with many practical examples. I hope that this approach will help you decide what to do when you face new situations in your current work.
acknowledgments The Manning team helped to create a high-level book, and I am looking forward to more opportunities of this kind. I would like to thank my professors and colleagues for all their support during the years and to the many participants in my face-to-face or online courses – they repre- sented a stimulus for me in achieving top quality work and always looking for improvement. Thanks to the co-authors of the book, Petar Tahchiev, Felipe Leme, Vincent Massol, and Gary Gregory, for strong first editions that represented a good foundation. I hope to meet all of you in person some day. Best thoughts for my col- league and friend Vladimir Sonkin, with whom I share the steps in investigating new technologies. I would also like to thank the staff at Manning: acquisition editor Mike Stephens, project editor Deirdre Hiam, development editor Katie Sposato Johnson, review edi- tor Mihaela Batinic, technical development editor John Guthrie, technical proofer David Cabrero, senior technical development editor Al Scherer, copyeditor Tiffany Taylor, and proofreader Katie Tennant. To all the reviewers: Andy Keffalas, Becky Huett, Burk Hufnagel, Conor Redmond, David Cabrero Souto, Ernesto Arroyo, Ferdinando Santacroce, Gaurav Tuli, Greg Wright, Gualtiero Testa, Gustavo Filipe Ramos Gomes, Hilde Van Gysel, Ivo Alexandre Costa Alves Angélico, Jean-François Morin, Joseph Tingsanchali, Junilu Lacar, Karthikeyarajan Rajendran, Kelum Prabath Senanayake, Kent R. Spillner, Kevin Orr, Paulo Cesar, Dias Lima, Robert Trausmuth, Robert Wenner, Sau Fai Fong, Shawn Ritchie, Sidharth Masaldaan, Simeon Leyzerzon, Srihari Sridharan, Thorsten P. Weber, Vittorio Marino, Vladimír Oraný, and Zorodzayi Mukuya. Your suggestions helped make this a better book.xv
about this book JUnit in Action is a book about creating safe applications and how to greatly increase your development speed and remove much of the debugging nightmare—all with the help of JUnit 5 with its new features, and other tools and techniques that work in con- junction with JUnit 5. The book focuses first on understanding the who, what, why, and how of JUnit. The first few chapters should convince you of the capabilities and power of JUnit 5. Following that, I take a deep dive into working effectively with JUnit 5: migrating from JUnit 4 to JUnit 5, testing strategies, working with JUnit 5 and different tools, working with modern frameworks, and developing applications with JUnit 5 according to present-day methodologies. Who should read this book This book is for application developers who are already proficient in writing Java Core code and are interested in learning how to develop safe and flexible applications. You should be familiar with object-oriented programming and have at least a working knowledge of Java. You will also need a working knowledge of Maven and be able to build a Maven project and open a Java program in IntelliJ IDEA, edit it, and launch it in execution. Some of the chapters require basic knowledge about technologies like Spring, Hibernate, REST, and Jakarta EE. How this book is organized: A roadmap This book has 22 chapters in five sections. Part 1 presents the JUnit 5 essentials: Chapter 1 gives you a quick introduction to the concepts of testing—knowledge you need to get started. You will get straight to the code, seeing how to write and execute a very simple test and see its results. xvi
ABOUT THIS BOOK xvii Chapter 2 discusses JUnit in detail; you will see JUnit 5’s capabilities and walk through the code that puts them in practice. Chapter 3 looks at the JUnit architecture. Chapter 4 discusses how to move from JUnit 4 to JUnit 5 and how to migrate projects between these versions of the framework. Chapter 5 is dedicated to tests as a whole. The chapter describes different kinds of tests and the scenarios to which they apply. It also discusses different levels of testing and the best scenarios in which to execute those tests. Part 2 presents different testing strategies: Chapter 6 is dedicated to analyzing test quality. It introduces concepts such as code coverage, test-driven development, behavior-driven development, and mutating testing. Chapter 7 is dedicated to stubs, taking a look at a solution to isolate the environ- ment and make tests seamless. Chapter 8 explains mock objects, providing an overview of how to construct and use them. Chapter 9 describes a different technique: executing tests in a container. Part 3 shows how JUnit 5 works with other tools: Chapter 10 provides a very quick introduction to Maven and its terminology. Chapter 11 guides you through the same concepts, this time using another pop- ular tool called Gradle. Chapter 12 investigates the way you can work with JUnit 5 by using the most popular IDEs today: IntelliJ IDEA, Eclipse, and NetBeans. Chapter 13 is devoted to continuous integration tools. This practice, which is highly recommended by extreme programmers, helps you maintain a code repository and automate the build on it. Part 4 shows how JUnit 5 works with modern frameworks: Chapter 15 introduces HtmlUnit and Selenium. You will see how to test the pre- sentation layer with these tools. Chapters 16 and 17 are dedicated to testing one of the most useful frameworks today: Spring. Spring is an open source application framework and inversion of control container for the Java platform. It includes several separate frameworks, including the Spring Boot convention-over-configuration solution for creating applications that you can run directly. Chapter 18 examines testing REST applications. Representational State Trans- fer is an application program interface that uses HTTP requests to GET, PUT, PATCH, POST, and DELETE data.
ABOUT THIS BOOKxviii Chapter 19 discusses alternatives for testing database applications, including JDBC, Spring, and Hibernate. Part 5 shows how JUnit 5 works with modern software development methodologies: Chapter 20 discusses project development using one of today’s popular devel- opment techniques: test-driven development. Chapter 21 discusses developing projects using behavior-driven development. It shows how to create applications that address business needs: applications that not only do things right but also do the right thing. Chapter 22 shows how to build a test pyramid strategy with the help of JUnit 5. It demonstrates testing from the ground level (unit testing) to the upper levels (integration testing, system testing, and acceptance testing). In general, you can read this book from one chapter to the next. But, as long as you master the essentials presented in part 1, you can jump directly to any chapter that addresses your current needs. About the code This book contains (mostly) large blocks of code, rather than short snippets. There- fore, all the code listings are annotated and explained. In some chapters, annotations in listings and their explanations in text are marked with a number and the prime character to indicate comparisons with lines in similar listings. You can find the full source code for all these examples by downloading it from GitHub at https://github .com/ctudose/junit-in-action-third-edition. liveBook discussion forum Purchase of JUnit in Action, Third Edition, includes free access to a private web forum run by Manning Publications where you can make comments about the book, ask technical questions, and receive help from the authors and from other users. To access the forum, go to https://livebook.manning.com/#!/book/junit-in-action-third- edition/discussion. You can also learn more about Manning's forums and the rules of conduct at https://livebook.manning.com/#!/discussion. Manning’s commitment to our readers is to provide a venue where a meaningful dialogue between individual readers and between readers and the authors can take place. It is not a commitment to any specific amount of participation on the part of the authors, whose contribution to the forum remains voluntary (and unpaid). We suggest you try asking them some challenging questions lest their interest stray! The forum and the archives of previous discussions will be accessible from the publisher’s website as long as the book is in print.
Comments 0
Loading comments...
Reply to Comment
Edit Comment