Accelerate Unit Testing
of Spring Applications
With Parasoft Jtest &
Unit Test Assistant
TECHNICAL WHITEPAPER
Accelerate Unit Testing of Spring Applications With Parasoft Jtest & Unit Test Assistant
Technical Whitepaper
2
INTRODUCTION
The Spring framework along with Spring Boot is one of the most popular Java enterprise soware
frameworks. Applicaons built with Spring share a common need to be stable, reliable, and secure.
In general, developers understand the proven track record of ensuring quality with unit tests but
would rather spend their me developing applicaon features. While it's a recognized best pracce,
80% of organizaons that do implement unit tesng achieve less than 40% code coverage, leaving
most of the code eecvely untested at the unit level.
Even with these relavely poor results, developers sacrice a lot of me and eort creang and
maintaining the unit tests that they do build. With the adopon of the Agile process, me is essenal,
and the burden of unit tesng is a boleneck for development teams.
The test automaon tooling that comes with Paraso Jtest improves this situaon by providing
a guided and automated approach to unit tesng, making it easier and more ecient. This paper
describes how Paraso Jtest’s Unit Test Assistant can improve the workow and outcomes for Spring
applicaon tesng.
Accelerate Unit Testing of Spring Applications With Parasoft Jtest & Unit Test Assistant
Technical Whitepaper
3
PARASOFT JTEST’S UNIT TEST ASSISTANT
Paraso Jtest’s Unit Test Assistant (UTA) is an IDE plugin that helps guide users through the unit
tesng pracce with easy one-click acons for creang, scaling, and maintaining unit tests. With
UTA, users can achieve higher code coverage and cut the me and eort spent on unit tesng in half,
all while reducing the specialized experse needed to build a comprehensive and meaningful suite of
JUnit test cases.
Paraso Jtest integrates with exisng technologies and is not a vendor locked soluon. It easily
integrates with the developer’s IDE (Eclipse or IntelliJ), while leveraging exisng open source
frameworks, such as JUnit for unit test creaon and execuon or Mockito for mocking. Since there
are no dependencies on Paraso libraries, it's simple and easy to run the tests created by Jtest in an
exisng connuous integraon (CI) process.
THE CHALLENGES OF TESTING SPRING APPLICATIONS
The Spring framework comes with nice support for integraon tesng, but a lot of manual coding is
required to set up test cases properly. Building and maintaining tests for Spring applicaons presents
developers with a unique set of challenges.
» The Spring framework must be initialized and configured.
» The application usually has third-party dependencies like persistent storage, external services,
and so on.
» Applications often use built-in Spring features for sessions, security, messaging, and the like.
These can be tricky to set up in test cases for developers who are new to Spring testing.
» Application dependencies such as beans need to be configured appropriately.
These challenges, combined with the fact that wring comprehensive and maintainable test suites
takes a lot of me in general, result in developers not wring enough tests. In turn, this leads to
security vulnerabilies, defects, and regressions, in addion to extra me and cost.
Jtest’s Unit Test Assistant helps by making the process of generang, improving, and maintaining
JUnit tests far easier and less me-consuming, so that developers can build good tests quickly and
get back to what they love—wring code.
INTEGRATION TESTING VS. UNIT TESTING
When building a test suite for your Spring applicaon, it's important to consider the type of tests
to use. Integraon tests validate many components of the applicaon together as a combined
enty. They provide the most realisc environment in which tests can run but require all related
components to be inialized and congured with real objects.
Although Spring provides libraries to simplify this conguraon in your tests, it can sll be complex to
set up, maintain, and debug. Addionally, the tests take a long me to run.
Accelerate Unit Testing of Spring Applications With Parasoft Jtest & Unit Test Assistant
Technical Whitepaper
4
Alternavely, unit tests isolate components in the applicaon for individual tesng. They run faster,
require less boilerplate code, and allow more exibility for developers to test corner and error cases.
But you also need to congure the dependencies for each component, usually as mocks. Mocking
code can be me-consuming to write, debug, and maintain.
Paraso generally recommends using a larger number of unit tests to validate the bulk of the
applicaon behavior and fewer integraon tests to ensure that the applicaon works properly as
a whole.
UNIT TESTING IN A SPRING APPLICATION
The Spring framework enables developers to dene applicaons quickly and easily using common
convenons, such as service and controller objects. In the following examples, we dene a controller
that interacts with a service and enty objects to implement a Spring MVC web applicaon.
An example Spring MVC controller:
This example controller implements a simple REST service to get items from a to-do list. It depends
on an ITodoService, whose implementaon contains the business logic.
To test the ndAll method, we need a JUnit test that does the following:
» Configures the ITodoService with configurable and stable behavior.
» Calls the findAll method with a valid Model argument.
» Validates the return value of findAll, plus the attribute added to the Model argument.
@Controller
public class TodoController {
@Autowired
private ITodoService service;
@GetMapping(“/t o d o )
public StringndAll(Model model) {
String category = (String) model.getAttribute("category");
List<Todo> todos = service. n d A ll(c at e g o r y);
model.addAttribute(“todos”, t o d o s);
return todo/list;
}
}
Accelerate Unit Testing of Spring Applications With Parasoft Jtest & Unit Test Assistant
Technical Whitepaper
5
An example JUnit test that does all of these things might look like this:
public class TodoControllerTest {
@InjectMocks
TodoController underTest;
@Mock
ITodoService service;
private AutoCloseable closeable;
@BeforeEach
public void setupMocks() {
closeable = MockitoAnnotations.openMocks(this);
}
@AfterEach
public void releaseMocks() throws Exception {
closeable.c lo se ();
}
@Test
public void t e s t Fi n d A l l() throws Throwable {
// G iv e n
List<Todo> ndAllResult = new ArrayList<Todo>();
doReturn(ndAllResult).when(service).ndAll(nullable(String
.class));
// W h e n
Model model = mock(Model.class);
String result = underTest.ndAll(model);
// Then
assertEquals("todo/list", result);
verify(model).addAttribute(“todos”, ndAllResult);
}
}
Accelerate Unit Testing of Spring Applications With Parasoft Jtest & Unit Test Assistant
Technical Whitepaper
6
The above example is a simple test, but there’s sll a lot of boilerplate code to write and a lot going on.
» The @InjectMocks annotation tells Mockito to automatically instantiate the object under test and
inject the ITodoService object into the controller for testing.
» The @Mock annotation on the ITodoService field tells Mockito to mock the service object as well.
Note the required setup and teardown methods to open and close mocks.
» The behavior of the ITodoService method is defined and a mocked Model is passed to the findAll
method under test. Finally, its return value is validated.
What’s wrong with the above test? Nothing. But imagine a more complex controller with mulple
handler methods that accept more arguments and produce more outputs.
Wring those addional tests would take a lot more me, especially if good tesng coverage is
important. In addion, most real tests require signicantly more conguraon for other services,
sessions and environments, security, and so on.
GENERATING UNIT TESTS WITH THE UNIT TEST ASSISTANT
Unit tests should be fully automated, predictable, and maintainable. However, creang such tests
manually is me consuming and requires focused eort and skills. Paraso Jtests Unit Test Assistant
helps solve these problems by removing the tedious and mundane parts of creang unit tests, freeing
the developer to focus on the business logic of those tests and ulmately create more meaningful,
maintainable test suites.
The Unit Test Assistant helps developers write Spring tests in mulple ways.
» Auto generates the boilerplate code for JUnit tests quickly.
» Auto configures input parameters and generates multiple tests for increased test coverage.
» Mocks dependencies to isolate the method under test and simplify the test.
» Analyzes test flow at runtime and provides recommendations with quick fixes to improve tests.
» Collects coverage data to find and address coverage gaps or identify and run tests impacted by
local changes.
Accelerate Unit Testing of Spring Applications With Parasoft Jtest & Unit Test Assistant
Technical Whitepaper
7
AUTO GENERATING TESTS
Generang tests with the Unit Test Assistant is straighorward. Select the method to be tested and
choose a test creaon acon:
Figure 1:
UTA view acons to
create tests
String ndAll(Model)
Regular
Create test suite Cover the line
The Regular acon will generate the simplest test case for the handler method, while the Create
test suite acon will generate a more comprehensive and precongured set of tests. When using the
Create test suite acon, the following dialog will appear allowing you to dene how you want the
test(s) to be congured.
Figure 2:
Bulk creaon dialog
For Spring applicaons, it's recommended to select the “Use @InjectMocks” opon. This opon
will congure the Unit Test Assistant to generate Mockito code that automacally injects all
dependencies for the object under test including transient dependencies such as service objects.
Since all dependencies are mocked, their behavior is congurable on a per test basis as shown in the
example above.
Accelerate Unit Testing of Spring Applications With Parasoft Jtest & Unit Test Assistant
Technical Whitepaper
8
Figure 3:
UTA view acons for
running tests
Figure 4:
Flow tree and
recommendaons aer
running tests
Aer tests run, the test execuon ow appears. The Unit Test Assistant recommends improvements
for the test and reports them in the IDE.
MOCKING DEPENDENCIES
In addion to the unit test automaon and guided test creaon covered above, the Unit Test
Assistant also helps with dependency management to accelerate test conguraon and reduce
maintenance.
Complex applicaons are not built from scratch. They use libraries, APIs, and core projects or
services that someone else might build and maintain. Spring developers oen leverage exisng
funconality so they can spend me and eort on the business logic of the applicaon. Although this
pracce can save developers from re-implemenng funconality that exists elsewhere, it also leads
to applicaons with lots of dependencies, as shown in red below.
RUNNING TESTS & ANALYZING RESULTS
Generated unit tests can be run using any normal JUnit runner. The Unit Test Assistant provides
toolbar acons that run the JUnit and analyze the test.
Figure 5:
A Spring service with
mulple dependencies
Contoller Service
Libraries
DB
Accelerate Unit Testing of Spring Applications With Parasoft Jtest & Unit Test Assistant
Technical Whitepaper
9
Figure 6:
A mocked service replaces
mulple dependencies
How do developers focus unit tests on the unit(s) under test (controller and service) if most of its
funconality depends on the behavior of these dependencies?
If the test were to use real dependencies, then it would end up being more like an integraon test,
which has disadvantages as discussed above. Addionally, somemes these dependencies aren’t
available in a tesng environment. When building unit tests, we need to isolate the code under
test from these dependencies in a stable and controllable way so that we can fully exercise the
isolated code.
One opon is to create specialized “tesng” versions of these dependencies. However, using a
standardized library like Mockito provides benets over this approach for mulple reasons.
» There's no need to write and maintain the special test code.
» Mocking libraries can track invocations against mocks, providing an extra layer of validation.
» Modern mocking libraries provide additional functionality, like mocking static methods, private
methods, or constructors.
» Knowledge of a mocking library like Mockito can be reused across projects, whereas custom
testing code often can’t be reused.
Dependencies in Spring
In general, Spring applicaons split funconality into beans. A controller might depend on a service
bean, and the service bean might depend on an EntyManager, JDBC connecon, or another bean.
Most of the me, the dependencies from which the code under test needs to be isolated are beans.
In an integraon test, it makes sense that all layers should be real, but for unit tests, a decision is
needed about which dependencies should be real and which should be mocks.
Although the Spring framework denes which dependent beans to inject using either XML, Java, or
a combinaon of both, unit tests do not run the full Spring framework. Therefore, mocks need to be
dened and injected by the test itself.
Service
Mocked Service
Libraries
DB
Contoller
Accelerate Unit Testing of Spring Applications With Parasoft Jtest & Unit Test Assistant
Technical Whitepaper
10
// W h e n
Model model = mock(M odel.class);
String result = underTest.ndAll(model);
The above JUnit example uses Mockito’s InjectMocks funconality to automacally create and inject
mock objects from the test. We dene all objects that need to be injected as elds in the test class
using the @Mock annotaon. Mockito does the rest.
Each test method can then congure these mocks as required to handle method calls (in the example
above, we handle the ndAll method), throw excepons, or any other behavior the test case needs.
Using the Unit Test Assistant to Automate Mocking
When the Unit Test Assistant generates a test for a specic method that inializes mocks using
@InjectMocks, all dependencies that the method uses are set up as mocks in the test class to ensure
they're injected when the test runs. This up-front conguraon is usually sucient for new tests, but
somemes addional tools are needed. For instance, new tests might be modied copies of others
and require customizaon or exisng tests may require mocks to be added or updated when changes
are made to the applicaon.
When the test is run, the Unit Test Assistant detects method calls made on mock objects. If the
mock has not yet been congured to handle that method call, UTA recommends that those methods
be mocked and provides a quick x to mock the method in the test.
For example, the test above uses a mocked Model argument to call the method under test:
In the method under test, a method call is made on the Model argument:
public String ndAll(Model model) {
String category = (String) model.getAttribute("category");
List<Todo> todos = service. n d A l l(c at e g o r y);
model.addAttribute(“todos”, todos);
return todo/list;
}
Accelerate Unit Testing of Spring Applications With Parasoft Jtest & Unit Test Assistant
Technical Whitepaper
11
Running the example test produces a recommendaon like the following:
When the “Mock it” quick x is applied, the test is updated:
The “getAributeResult” can now be congured according to what the test needs, for example, using
a string with a real value since this is what the code under test expects.
Figure 7:
Mockable method
recommendaon
// W h e n
Model model = mock(M odel.class);
Object getAttributeResult = new Object(); // UTA: default value
when(model.getAttribute(nullable(St ri ng.class))).
thenReturn(getAttributeResult);
String result = underTest.ndAll(model);
public class ExternalPersonService {
public static Person getPerson(int id) {
RestTemplate restTemplate = new RestTemplate();
try {
return restTemplate.getForObject(“http://domain.com/
people/ + id, Person.class);
} catch (RestClientException e) {
return null;
}
}
}
Mocking Stac Methods
Somemes dependencies are accessed stacally. For example, an applicaon might access a third-
party service through a stac method call:
Accelerate Unit Testing of Spring Applications With Parasoft Jtest & Unit Test Assistant
Technical Whitepaper
12
In the controller:
In this example, the handler method uses a stac method call to get a person object from a third-
party service. When we build a JUnit test for this handler method, a real HTTP call would be made to
the service each me the test is run.
Instead, let’s mock the stac ExternalPersonService.getPerson() method. This prevents the HTTP
call and allows us to provide a Person object response that suits our tesng needs. The Unit Test
Assistant can mock stac methods like this automacally when a new test is generated. To enable
this, congure stac methods that need to be mocked in Paraso Preferences.
@GetMapping
public ResponseEntity<Person> getPerson(@PathVariable(“id) int id, Model model)
{
Person person = ExternalPersonService.getPerson(i d);
if (person != null) {
return new ResponseEntity<Person>(person, HttpStatus.OK);
}
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
Figure 8:
Mocking preferences
for stac methods and
constructors
Accelerate Unit Testing of Spring Applications With Parasoft Jtest & Unit Test Assistant
Technical Whitepaper
13
Here, Unit Test Assistant is congured to mock all stac calls to ExternalPersonService. You can
specify parcular methods, constructors, or all methods using wildcards (*) as shown above in the
class to be mocked.
When generang a new test for the example code above, the test will look like this:
Here, Unit Test Assistant includes Mockito code to mock ExternalPersonService.getPerson(), including
a mocked person for the handler method to use.
public class PeopleControllerTest {
Set<AutoCloseable> mocks = new Ha s h Set<>();
@After
public void closeMocks() throws Throwable {
for (AutoCloseable mocked : mocks) {
m o c k e d.clo s e();
}
}
@Test
public void testGetPerson() throws Throwable {
// G iv e n
MockedStatic<ExternalPersonService> mocked =
mockStatic(ExternalPersonService.class);
mocks.a d d (m o c k e d);
Person getPersonResult = mock(Person.class);
mocked.when(() -> ExternalPersonService.getPerson(anyInt())).
thenReturn(getPersonResult);
PeopleController underTest = new PeopleController();
// W h e n
int id = 0; // UTA: default value
ResponseEntity<Person> result = underTest.getPerson(id);
// Then - assertions for result of method getPerson(int)
assertNotNull(r e s u lt);
}
}
Accelerate Unit Testing of Spring Applications With Parasoft Jtest & Unit Test Assistant
Technical Whitepaper
14
The Unit Test Assistant can also add stac mocks to exisng tests in cases where the test already
exists. For instance when source changes require new mocks to be added. Consider the following
example test.
When the test is run, we can see the HTTP call being made in the Unit Test Assistant Flow Tree.
We can update the test to mock the call to ExternalPersonService.getPerson() instead:
@Test
public void testGetPerson() throws Throwable {
// G iv e n
PeopleController undertest = new PeopleController();
// W h e n
int id = 1;
Model model = mock(M odel.class);
ResponseEntity<Person> result = underTest.getPerson(id, model);
// Then
assertNotNull(result);
assertNotNull(result.getBody());
}
Figure 9:
Stac mocking acons
from test ow tree
Accelerate Unit Testing of Spring Applications With Parasoft Jtest & Unit Test Assistant
Technical Whitepaper
15
The test is updated to mock the stac method for this test using Mockito:
@Test
public void testGetPerson() throws Throwable {
MockedStatic<ExternalPersonService> mocked =
mockStatic(ExternalPersonService.class);
mocks.a d d (m o c k e d);
Person getPersonResult = null; // UTA: default value
mocked.when(() -> ExternalPersonService.getPerson(anyInt())).
thenReturn(getPersonResult);
// G iv e n
PeopleController underTest = new PeopleController();
// W h e n
int id = 1;
Model model = mock(M odel.class);
ResponseEntity<Person> result = underTest.getPerson(id, model);
// Then
assertNotNull(r e s u lt);
assertNotNull(result.getBody());
}
Set<AutoCloseable> mocks = new HashSet<>();
@AfterEach
public void closeMocks() throws Throwable {
for (AutoCloseable mocked : mocks) {
mocked.close();
}
}
Accelerate Unit Testing of Spring Applications With Parasoft Jtest & Unit Test Assistant
Technical Whitepaper
16
Using the Unit Test Assistant, select the getPersonResult variable and instanate it so that the
mocked method call doesn’t return null:
When the test is run again, getPersonResult is returned from the mocked ExternalPersonService.
getPerson() method, and the test passes.
Note: From the ow tree, its possible to choose “Add Mockable Method paern” for stac method
calls. This congures the Unit Test Assistant to always mock those stac method calls when
generang new tests.
THE SPRING MVC TEST FRAMEWORK
As discussed previously, integraon tests validate many components of the applicaon together as a
combined enty. They provide the most realisc environment in which tests can run but require all
related components to be inialized and congured with real objects.
For integraon tesng, the Spring Framework includes a tesng framework that makes tesng
controllers, services, and other components much easier. It includes funconality for conguring
the Spring test container, invoking controller handler methods, and validang behavior with custom
asserons.
To test the ndAll method in our example controller with an integraon test, we need a JUnit test
that does the following.
» Configures the Spring container with the controller under test and an ITodoService that
TodoController depends on.
» Sends a valid request to the findAll handler method.
» Validates elements of the response, including the return value (“todo/list”) and Model attribute
todos”.
String name = "na me"; // UTA: default value
int age = 0; // UTA: default value
Person getPersonResult = new Person(name, age);
Accelerate Unit Testing of Spring Applications With Parasoft Jtest & Unit Test Assistant
Technical Whitepaper
17
An example Spring MVC JUnit test may look like this:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConguration
public class TodoControllerTest {
@Autowired
TodoController controller;
@Autowired
ITodoService todoService;
MockMvc mockMvc;
@Before
public void setup() {
mockMvc = MockMvcBuilders.standalo neSetup(controller).b u ild();
}
@Conguration
static class Cong {
@Bean
public TodoController getTodoController() {
return new To d o C o n t ro lle r();
}
@Bean
public ITodoService getTodoService() {
return new To d o Ser v i ce();
}
}
@Test
public void t e s t Fi n d A l l() throws Exception {
mockMvc.perfor m(get(“/t o d o )).a n d E x p e c t (view().n a m e (“todo/
list”));
}
}
Accelerate Unit Testing of Spring Applications With Parasoft Jtest & Unit Test Assistant
Technical Whitepaper
18
As with the plain JUnit example above, this simple test has plenty of boilerplate code to write and
a lot going on. In this example, the Spring framework is congured with a controller and its services
using an inner conguraon class. The MockMvc funcons are used to send a request to the handler
method using perform() and validate the returned view name using andExpect().
In real applicaons, the controller and service code are usually more complex with mulple handler
methods that accept more arguments and produce more outputs. Once again, wring the tests could
take a lot of me, especially if good tesng coverage is important. In addion, most real tests require
signicantly more conguraon like XML or class, sessions and environments, security, and so on.
GENERATING SPRING INTEGRATION TESTS WITH THE UNIT TEST ASSISTANT
Paraso Jtest’s Unit Test Assistant helps create Spring MVC integraon tests automacally, freeing
developers to focus on the business logic of those tests and ulmately creang more meaningful,
maintainable test suites.
The Unit Test Assistant provides Spring-specic features to help developers write Spring
integraon tests.
1. Auto generating the boilerplate code for Spring MVC tests quickly.
2. Auto generating multiple tests with pre-configured input values for increased test coverage.
3. Mocking dependencies for injection into the controller to isolate the handler method and
simplify the test.
4. Providing Spring-specific recommendations with quick-fixes to improve tests.
Auto Generang Tests
Before generang Spring integraon tests, select the checkbox to enable the feature in Paraso
preferences. This enables special acons in the UTA view.
Figure 10:
Enabling Spring MVC test
acons
Accelerate Unit Testing of Spring Applications With Parasoft Jtest & Unit Test Assistant
Technical Whitepaper
19
Choosing "Regular Spring" auto generates the boilerplate Spring MVC test automacally, including
the conguraon classes and all beans that the controller depends on.
The mockMvc.perform() call is added and precongured to invoke the handler method for which
the test was created. The Unit Test Assistant even adds some example asserons that you can
uncomment and congure.
The Unit Test Assistant supports test generaon using XML or class conguraon by seng the
“Default ContextConguraon aributes” opon in preferences.
Spring Boot
Since Spring Boot provides simplied conguraon for beans as well as addional annotaons for
tests, the Unit Test Assistant generates slightly dierent tests when it detects Spring Boot in your
project. For example, MockMvc is autowired, dependencies are mocked with @MockBean, and the
@SpringBootTest annotaon is used.
Providing Handler Method Inputs
Handler methods are oen congured to accept path, query, or other parameters as arguments to
the method. To test the MVC handler method, MockMvc is used to build the path/query and any
other parameters needed to invoke the method.
The Unit Test Assistant auto congures the mockMvc.perform() call to invoke the handler method.
Individual parameters show up in the test as local variables or parameters in a parameterized test that
need to be congured for the test to run properly.
For example:
Here, the “id” has been preset to a valid value, which becomes part of the path for Spring to match.
@Test
public void testGetPerson() throws Throwable {
// W h e n
int id = 1;
ResultActions actions = mockMvc.perfor m(get(/people/ + i d ));
}
Generang Spring integraon tests with the Unit Test Assistant is straighorward. Select a Spring
handler method in the IDE for the controller and choose a test creaon acon.
Figure 11:
UTA view acons for
creang Spring MVC tests
Accelerate Unit Testing of Spring Applications With Parasoft Jtest & Unit Test Assistant
Technical Whitepaper
20
The Unit Test Assistant looks for various types of handler method parameters and automacally
prepares the test for them. For example, if the handler method needs the HpSession, it might look
like this:
Unit Test Assistant will prepare the generated test with an HpSession so that it can be congured to
match the needs of the handler method and the test for it.
Unit Test Assistant does this for a variety of parameter types, including:
» HttpSession adds an example se t Att ri b u t e() call.
» Headers adds a h e a d e r() call.
» Request body adds a payload variable and content() call.
» Authentication adds an example instantiation to the setup method and a principal() call.
@GetMapping("/save")
public ModelAndView save(HttpSession session, Model model)
{
// Interact with session, using methods like getAttribute or
setAttribute
return new ModelAndView("save.jsp", model.asMap());
}
@Test
public void testSave() throws Throwable {
// W h e n
MockHttpSession session = new MockHttpSession();
// session.setAttribute("", "");
ResultActions actions = mockMvc.perfor m(get("/save").
session(session));
// Then
actions.andExpect(status().i s O k());
}
Accelerate Unit Testing of Spring Applications With Parasoft Jtest & Unit Test Assistant
Technical Whitepaper
21
Figure 12:
No handler method
was called during test
execuon
This indicates that the test inputs are likely not congured to match the expected handler method’s
RequestMapping.
VALIDATING HANDLER METHOD OUTPUTS
Depending on what the handler method is supposed to provide to callers, it may return a variety
of types. Most of the me, handler methods return a ModelAndView or similar objects like Model or
RedirectView to serve a page or a ResponseEnty of some kind. Somemes they only return the raw
object to be serialized. This response is accessible to the Spring MVC Test framework for validaon.
For example, the following asserons were added by the Unit Test Assistant for a handler method
that returns a ModelAndView:
Once the test is generated, these asserons can be uncommented and populated with values to
quickly build a useful and valuable test. If an asseron fails at runme, the Unit Test Assistant
provides a recommendaon and quick x to automacally update the expected value or remove the
asseron.
// W h e n
int id = 1;
ResultActions actions = mockMvc.perfor m(get(/people/ + i d ));
// Then
// actions.andExpect(status().isOk());
// actions.andExpect(header().string(, “));
// actions.andExpect(view().name());
// actions.andExpect(model().attribute(, “));
Note: Running a test that does not cause the handler method to be invoked—for example, if the
test inputs are not congured properly, Spring may not match the request to the handler method—
produces a recommendaon like the following:
Accelerate Unit Testing of Spring Applications With Parasoft Jtest & Unit Test Assistant
Technical Whitepaper
22
To quickly set up the asseron with a proper value, follow these steps.
1. Uncomment an assertion.
2. Run the test.
3. Inspect the results expecting failure in this case.
4. Use a quick fix to set the correct expected value.
Mocking Dependencies in a Spring MVC Test
Because Spring applicaons split funconality into beans, and controllers oen depend on mulple
other beans, it makes sense that some integraon tests will need real beans, while other beans may be
mocks. For instance, if a real database is not praccal, it may sll need to be mocked even if all service
objects are real.
Spring allows developers to dene and congure beans using either XML, Java, or a combinaon
of both to provide a mixture of mocked and real beans in an applicaon conguraon. Since mock
objects need to be dened in Java, a conguraon class should be used to dene and congure the
mocked beans.
Using the Unit Test Assistant to Automate Mocking
When the Unit Test Assistant generates a Spring test, all dependencies for a controller are set up
as mocks so that each test gains control over the dependency. When the test is run, the Unit Test
Assistant detects method calls made on a mock object for methods that do not yet have method
mocking congured and recommends that those methods should be mocked. This quick x is used to
automacally mock each method.
Here's an example controller that depends on a PersonService:
@Controller
@RequestMapping(/people”)
public class PeopleController {
@Autowired
protected PersonService personService;
@GetMapping
public ModelAndView people(Model model){
for (Person person : personService.getAllPeople()) {
model.addAttribute(person.getName(), person.getAge());
}
return new ModelAndView(“people.jsp”, model.asMap());
}
}
Accelerate Unit Testing of Spring Applications With Parasoft Jtest & Unit Test Assistant
Technical Whitepaper
23
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConguration
public class PeopleControllerTest {
@Autowired
PersonService personService;
// Other elds and setup
@Conguration
static class Cong {
// Other beans
@Bean
public PersonService getPersonService() {
return mock(PersonService.class);
}
}
@Test
public void testPeople() throws Exception {
// W h e n
ResultActions actions = mockMvc.perfor m(get(/people”));
}
}
And an example test, generated by the Unit Test Assistant:
Figure 13:
Mockable method
recommendaon
Here, the test uses an inner class annotated with @Conguraon, which provides bean dependencies
for the controller under test using Java conguraon. This allows us to mock the PersonService in
the bean method. No methods are mocked yet. When the test is run in Paraso Jtest, the following
recommendaon appears:
Accelerate Unit Testing of Spring Applications With Parasoft Jtest & Unit Test Assistant
Technical Whitepaper
24
When the test is run again, it passes. The collecon object that gets returned by getAllPeople() should
next be populated. However, the challenge of seng up the mocked dependencies is solved.
Note: It's possible to move the generated method mocking from the test method into the
conguraon class’ bean method. If this is done, it means that each test in the class mocks the same
method in the same way. Leaving the method mocking in the test method means that the method
can be mocked dierently between dierent tests.
Mocking With Spring Boot
Spring Boot makes bean mocking even easier. Instead of using an @Autowired eld for the bean in the
test and a conguraon class that denes it, use a eld for the bean and annotate it with @MockBean.
Spring Boot will create a mock for the bean using the mocking framework it nds on the classpath
and inject it the same way any other bean in the container can be injected. When generang
Spring Boot tests with the Unit Test Assistant, the @MockBean funconality is used instead of the
conguraon class.
@SpringBootTest
@AutoCongureMockMvc
public class PeopleControllerTest {
// Other elds and setup – no Conguration class needed!
@MockBean
PersonService personService;
@Test
public void testPeople() throws Exception {
...
}
}
@Test
public void testPeople() throws Exception {
Collection<Person> getAllPeopleResult = new
ArrayList<Person>();
doReturn(getAllPeopleResult).when(personService).getAllPeople();
// W h e n
ResultActions actions = mockMvc.perfor m(get(/people”));
}
This means that the getAllPeople() method was called on the mocked PersonService object, but the
test does not yet congure mocking for this method. Choosing the “Mock it” quick x opon, the
test is updated.
Accelerate Unit Testing of Spring Applications With Parasoft Jtest & Unit Test Assistant
Technical Whitepaper
25
XML vs Java Conguraon
In the rst example above, the conguraon class provided all the beans to the Spring container.
Alternavely, XML conguraon can be used for the test instead of the conguraon class or a
combinaon of the two. For example:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConguration({ classpath:/**/testContext.xml })
public class PeopleControllerTest {
@Autowired
PersonService personService;
// Other elds and setup
@Conguration
static class Cong {
@Bean
@Primary
public PersonService getPersonService() {
return mock(PersonService.class);
}
}
// T e s t s
}
Here, the class references an XML conguraon le in the @ContextConguraon annotaon
(not shown here) to provide most beans, which could be real beans or test-specic beans. A
@Conguraon class is also provided, where PersonService is mocked.
The @Primary annotaon indicates that even if a PersonService bean is found in the XML
conguraon, this test uses the mocked bean from the @Conguraon class instead. This type of
conguraon can make tesng code smaller and easier to manage. Its possible to congure the Unit
Test Assistant to generate tests using any specic @ContextConguraon aributes as needed.
Accelerate Unit Testing of Spring Applications With Parasoft Jtest & Unit Test Assistant
Technical Whitepaper
26
CONCLUSION
Spring combined with Spring Boot is the leading enterprise Java applicaon framework. As such, it
needs an appropriate level of tesng to ensure the quality and security of applicaons built with it.
Unfortunately, this level of tesng is not being achieved currently, mostly due to a lack of me and
the amount of manual coding and maintenance required.
Complex applicaons oen have funconal dependencies that complicate and limit a developers
ability to unit test their code. A healthy mix of unit and integraon tests can be eecve in
thoroughly tesng Spring applicaons. However, both must address the need to populate and control
dependencies for the code under test.
Using a mocking framework like Mockito can help developers isolate the code under test from these
dependencies, enabling them to write beer unit tests more quickly. Spring MVC integraon tests
can validate applicaon behavior in a realisc way with a mixture of real and mocked dependencies.
The Paraso Jtest Unit Test Assistant provides unit test automaon and guided test creaon with
dependency management to accelerate unit test generaon and reduce maintenance.
TAKE THE NEXT STEP
Request a demo to see how Jtest's Unit Test Assistant can help your team generate unit tests
quickly, work more eciently, and improve Java code quality.
ABOUT PARASOFT
Paraso helps organizaons connuously deliver quality soware with its market-proven, integrated
suite of automated soware tesng tools. Supporng the embedded, enterprise, and IoT markets,
Paraso’s technologies reduce the me, eort, and cost of delivering secure, reliable, and compliant
soware by integrang everything from deep code analysis and unit tesng to web UI and API
tesng, plus service virtualizaon and complete code coverage, into the delivery pipeline. Bringing
all this together, Paraso’s award-winning reporng and analycs dashboard delivers a centralized
view of quality enabling organizaons to deliver with condence and succeed in today’s most
strategic ecosystems and development iniaves—security, safety-crical, Agile, DevOps, and
connuous tesng.