Book Review: Integration Testing from the Trenches
On the subject of testing, the variety of definitions you hear in the industry is as diverse as the blind men's descriptions of an elephant.
But in his important and thorough treatise “Integration Testing from the Trenches” Nicolas Frankel starts from basic definitions and develops the concepts of integration testing with a casual formalism that's intuitive and fun.
The fundamental premise is that Unit Testing is the testing of one thing, usually a method, in contrast to Integration Testing, which is the testing of two or more things. Therefore in unit testing, calls out by the method under test are preferably stubbed-in or mocked so that only that method’s algorithm is tested, in isolation.
This simplifies conceptually the notion of unit testing, particularly of how to test methods calling methods calling methods, because according to our definition, you don't call them at all, for then they would be “integration tests.”
The book posits early on that Integration tests are brittle and hard to diagnose, so they should not be used instead of unit tests, and that is the reason that continuous integration servers generally measure coverage of unit tests but not integration tests.
Most of the time, Integration Testing is either crudely defined, wrongly understood or imperfectly used. In order to maximize the ROI, the most important guideline should be: the larger the SUT (System Under Test), the lesser the required code coverage
The book summarizes the first chapter with an honorable mention to a variety of related test categories:
- Mutation testing
- Functional testing
- Security testing
- Performance testing
Chapter two provides an excellent explanation of why integration tests can validly be ordered and how.
Unit testing frowns on tests ordering, for test cases should not rely on each other or on state. However, what goes for unit testing should not always blindly be applied to integration testing. In particular, having multiple ordered fine-grained methods with each method asserting the state of the system may be required for white-box testing.
The chapter covers JUnit in depth (using annotations introduced in JUnit 4.x), including the JUnit lifecycle callbacks and assertions, with detailed sample code.
It starts with a definition and brief discussion of the single assert rule:
Each test method should only provide a single assert, being the raison d’etre of the test method, or a tightly bound group of asserts, for example:
Assert.assertNotNull(list); Assert.assertFalse(list.isEmpty()); Assert.assertEquals(1, list.size());
This way, each assert is a little more restrictive than the previous and if the test fails, we will know exactly the reason (the list was null, it was empty or it had more than a single element).
The chapter also provides a nice treatment of various alternative frameworks to JUnit, discussing advantages over JUnit The book covers some esoteric JUnit options for sequencings tests in a deterministic fashion, that many developers probably have not seen before:
JUnit provides some basic feature regarding ordering. One can choose to order by annotating the test class with org.junit.@FixMethodOrder and use one of the three following value:
- org.junit.runners.JVM for no ordering at all
- org.junit.runners.DEFAULT for deterministic but not predictable ordering
- org.junit.runners.NAME_ASCENDING for ordering based on method name
Chapter 3 begins with a discussion of “Test-Friendly Design”, covering popular design patterns that make code more testable. Following that is a discussion of stubs, fakes, mocks, and dummies, and a code example that clarifies these in the context of dependency injection
The books then segues into a list of various mocking frameworks including Spring Test and MockRunner for creating fakes, and then does a deep dive into the popular Mockito framework for stubs, mocks, and dummies.There is also a brief discussion of using Mockito for Behavior Driven Development, simulating “Given-When-Then” behavior.
In general the book does not just list Api’s, rather it explains them and then summarizes them with a list in a format that produces clarity.
In the next section, there is a discussion of fakes using the Spring Test framework, diving in to Servlets and JNDI with ample code snippets. Spring Test conspicuously omits JMS, so the book next discusses MockRunner, which provides fakes for JMS, Struts, Servlets, Taglibs, JDBC, EJB, JMS, and JCA.
For each framework the book covers options and discusses the decision tree for selecting the right framework for your use case.
The next chapter deals with a frank discussion on how to test real resources such as time for example mocking System.currentTimeMillis() and using Joda Time (now replaced with Java 8 Date Time API’s), files, databases (traditional and NoSql, e.g. MongoDB), mail, and FTP, all using fakes. A great treatment of the popular DBUnit framework is included. As is prevalent throughout the book, the chapter recommended best practices and best tools.
The chapter concludes with a discussion of when to use stubs and when to use fakes:
Having more than one option always bring the quandary of choice. In most contexts, it is better to use the Fake server as it
- requires less effort and
- makes code more readable.
It is recommended to use the Stub server only if testing requisites really require it.
Subsequent chapters deal with a variety of topics including Web Service Integration (SOAP and REST) and associated tools and faking frameworks, Automated Testing (Build tools such as Maven and Gradle, Continuous Integration servers such as Bamboo, Hudson, and Jenkins)
The book concludes with a reference appendix for all of the frameworks and tools mentioned throughout the book.
I found after reading this book that some of the fear of the unknown that I normally experience when embarking on test creation has evaporated.
This is an important and thorough book that covers all facets of Integration testing, with a large overlap of unit testing and other testing techniques.
It is a must have reference for all software developers and project managers using any language. It is clear, easy to read, and comprehensive. The book is replete not just with Apis but with best practice advice as well, as well as many helpful examples
About the Book Author
Nicolas Fränkel operates as a successful Java and Java EE software architect and developer with more than 12 years experience in consulting for different clients. He also practices as trainer and a part-time lecturer in different French and Swiss higher education institutions, so as to broaden his understanding of software craftsmanship. Nicolas has also been a speaker at miscellaneous Java-related conferences in Europe, such as Deovxx Belgium, JEEConf, JavaLand and some Java User Groups and is the author of Learning Vaadin and Learning Vaadin 7.