|
Testing the Task List Service
At this point, you’ll add a test case for quality control thus far. The Spring Framework includes
excellent support for JUnit testing (which requires a Spring application context). While using the
Spring Framework's JUnit test classes, an elegant way to include the ability to participate in
dependency injection is to create a base class from which the test cases will extend. If you’re
testing a Spring Framework application that does not participate in transactions, use the org.springframework.test.AbstractDependencyInjectionSpringContextTests
class. By extending the AbstractDependencyInjectionSpringContextTests class, you’re
allowing Spring to inject the beans within the test cases. This makes your test cases first-class
clients of Spring. This test case needs to test the execution of the task service so, add a
protected field named the same as the bean ID in the application context file: tasklist-core.xml.
By default, protected fields will not be populated, so you need to tell Spring to populate them by
calling setPopulateProtectedVariables(true) within the constructor. The entire
ApplicationContextTest class can be seen in
Listing 2.
The TestServiceTest class in
Listing 3 extends ApplicationContextTest
and includes a method for testing a successful task creation.
You may have noticed a protected field called successfulCreateTask of type Task
that isn’t initialized.. That is because here, you will be performing your test bean
initialization within a test application context using Spring. At this point, your test bean
definitions should look like
Listing 4.
To allow the TestServiceTest class to use the test beans, add a new configuration
location within the ApplicationContextTest class. Your ApplicationContextTest's
configLocations method should now look like this:
<Application Context Test:configLocation after test-beans has been added>
protected String[] getConfigLocations() { return new String[] {
"classpath:jbriscoe/article/spring/validation/tasklist-core.xml",
"classpath:jbriscoe/article/spring/validation/tasklist-test.xml" }; }
TestServiceTest could have easily performed it's own initialization of a valid Task
object however, you are now able to inject the same test bean within another test case class. If you
need to change a bean's value, it will be reflected everywhere the bean is required. Running your
test case, you should see output similar to that shown in
Figure 2.

Figure 2. The Output from the Test Case:
Running your test case, you should see similar output.
Adding Validation
You now have the base functionality complete for the task service but it is missing some key
requirements. If someone wanted to create a new task, they could enter incomplete or fictitious
information, so you’ll need a safe way to apply your business rules—while preserving the
integrity and simplicity of the service. Luckily, the org.springframework.validation
package contains everything you need to validate your domain model. Spring includes a base Validator
interface for classes that need to implement their own custom validation. It contains two methods
which you’ll need to implement for each of your own domain model validators. The Validator
class’ supports method potentially contains duplicate code for all of the domain
model validators, so extract it's implementation into an abstract DefaultValidator
class:
package jbriscoe.article.spring.validation.validator;
import org.springframework.validation.Errors;
import org.springframework.validation.Validator;
public abstract class DefaultValidator implements Validator {
public boolean supports(final Class clazz) {
return clazz.isAssignableFrom(getValidatorSupportClass());
}
public abstract void validate(final Object obj, final Errors errors);
protected abstract Class getValidatorSupportClass();
}
Now, all new domain model validators will extend the DefaultValidator class and
implement the validate and getValidatorSupportClass methods. getValidatorSupportClass
is a simple method used by the DefaultValidator class to determine what domain model
class should be validated. So, for the TaskValidator class, the method getValidatorSupportClass
should return Task.class. The TaskValidator class shown in
Listing 5 contains all necessary validation for a single
Task object. This is important to keep in mind since you are not validating Employee
or Address objects within this class. Instead, you create an EmployeeValidator
and AddressValidator class that include their own validation rules. Validating on a per
object basis like this gives you the advantage of separating the concerns of your business
requirements, which makes solutions to complex problems relatively simple. Thus, a TaskValidator
should not know how to validate an Employee object's employee identifier and vice
versa.
The TaskValidator also demonstrates some common validation methods provided by Spring's
ValidationUtils class. The ValidationUtils class is not a one-size fits
all class and it isn't intended to be—use the commons-validator library for more complex
validation.
Author’s Note: If you haven’t already used the commons-validator project, it’s a
collection of common validation classes you can use while working with data. It’s quite
useful—some of the most mundane validation problems have already been solved in that library.
Looking at the TaskValidator, you will notice that the validate method contains two
arguments of type Object and Errors, respectively. The Object
argument contains the domain model object to be validated, such as Task. The Errors
object is a Spring class that contains some basic management methods for handling validation
errors—think of it as a kind of wrapper for validation errors. If the application encounters a
validation error, it will be added to the Errors object along with some other
contextual information about the error, like an an error code or message. The majority of the TaskValidator's
code consists of calendar arithmetic to ensure good data was provided, allowing your service to meet
it's requirements. The EmployeeValidator (
Listing 6) and AddressValidator (
Listing 7) contain similar code.
New on the Java Boutique:
New Review:
Time Management Made Easy with the Quartz Enterprise Job Scheduler
Why not just use the Java timer API? This open source scheduling
API boasts simplicity, ease-of-integration, a well-rounded feature
set, and it's free!
New Applet:
Reverse Complement
Reverse Complement is a simple applet that converts DNA or RNA
sequences into three useful formats.
Elsewhere on internet.com:
WebDeveloper Java
Lots of Java information on webdeveloper.com
WDVL Java
Thorough Java resource at the Web Developer's Virtual Library.
ScriptSearch Java
Hundreds of free Java code files to download.
jGuru: Your View of the Java Universe
Customizable portal with online training, FAQs, regular news updates, and tutorials.
|