Chapter 5. Testing the DAO Layer with Spring and JUnit

Everyone would agree that software testing should be a fundamental part of the development process. Thorough testing will ensure that the business requirements are met, the software works as expected, and that the defects are discovered before your client finds them. Although testing can never completely identify all the bugs, it is commonly believed that the earlier an issue is found, the cheaper it is to fix. It is far quicker to fix a NullPointerException in a block of code during development than when the system has been deployed to your client's production server. When developing enterprise systems, it becomes even more critical to deliver high-quality code. The reputation of your company is at stake; identifying and fixing issues before delivery is an important reason to make testing a critical part of the development lifecycle.

There are many different types of testing, including but not limited to, unit testing, integration testing, regression testing, black/white box testing, and acceptance testing. Each of these testing strategies could warrant a chapter in their own right but are beyond the scope of this book. An excellent article covering software testing in general can be found here: https://en.wikipedia.org/wiki/Software_testing. We will focus on unit testing.

Unit testing overview

Unit testing is a strategy for testing discrete units of source code. From a programmer's perspective, a unit is the smallest testable part of an application. A unit of source code is usually defined as a public method that is callable within the application and has a specific purpose. Unit testing of the DAO layer will ensure that each public method has at least one appropriate test case. In practice, we will need many more test cases than just a single one for each public method. For example, every DAO find(ID) method requires at least two test cases: one with an outcome returning a valid found object and one with an outcome that does not find a valid object. As a result, for every line of code written, developers often need several lines of test code.

Unit testing is an art form that takes time to master. Our goal is to establish a set of tests that cover as many scenarios as possible. This is inherently opposite to what we are trying to achieve as developers, where our goal is to ensure that a task is performed to meet the precise functional requirements. Consider the following business requirement: take the cost value in cents and convert it to the euro equivalent according to the exchange rate of the day.

The solution may seem self-explanatory, but what happens if the exchange rate is not available? Or the date is in the future? Or the cost value is null? What is the expected behavior if the value cannot be calculated? These are all valid scenarios that should be considered when crafting test cases.

With unit testing we define how the program should behave. Each unit test should tell a well-documented story of how that part of the program should act in a specific scenario. The tests become a contract that describes what should happen from the client code's point of view under the various reproducible conditions.

The benefits of unit testing

Unit testing gives us confidence that the code we have written works correctly. The unit testing process also encourages us to think about how our code will be used and what conditions need to be met. There are many benefits including:

  • Identifying problems early: Unit tests will help identify coding issues early in the development lifecycle when it is far easier to fix.
  • Higher quality: We don't want customers to find bugs, resulting in downtime and expensive release cycles. We want to build software that has as few bugs as possible in the first place.
  • Confidence: Developers are reluctant to touch code that is fragile. Well-tested code with solid test cases can be approached with confidence.
  • Regression proofing: Test cases build and evolve with the application. Enhancements and new functionalities may break the old code silently, but a well-written test suite will go a long way in identifying such scenarios.

Enterprise applications, with many programmers doing parallel development across different modules, are even more vulnerable. Coding side effects may result in far-reaching consequences if not caught early.

Note

A helper method was used to trim a Java String passed in as an argument. The argument was tested for null and the method returned an empty string " " if this was the case. The helper method was used everywhere in the application. One day, a developer changed the helper method to return null if the passed-in argument was null (they needed to identify the difference between null and an empty string). A simple test case would have ensured that this change did not get checked in to version control. The sheer number of null pointer exceptions when using the application was amazing!

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.139.239.41