Testing Spring components with Mockito

Be able to unit test your spring components without the need of loading the full spring-context with its ad-hoc test configurations it is ,in my opinion, a great advantage because it’s clean, easy to maintain, faster to write, smooth to alter.

A way to achieve this goal is to use Mockito and tell him to replace the @Autowired components in the class you want to test, with Mocks ( or Spies ).

Here an example.

We have a service called SalaryService that guess what, is calculating a hypothetical net salary based on the employee id passed. Easy concept.

The service required to collaborators, one, the EmployeeDAO, to retrieve the gross salary and a second one, the TaxCalculator, to apply some taxes based on the gross salary.

package com.marco.springmockito;
import java.math.BigDecimal;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class SalaryService {

    private static final BigDecimal minimumSalary = new BigDecimal(20000);

    @Autowired
    private EmployeeDAO employeeDAO;

    @Autowired
    private TaxCalculator taxCalculator;

    public BigDecimal getNetSalary(long employeeId) {
        BigDecimal netSalary = null;
        BigDecimal grossSalary = employeeDAO.getAnnualSalary(employeeId);
        BigDecimal taxes = taxCalculator.calculateTaxes(grossSalary);
        if (taxedSalaryIsGreaterThanMinimumSalary(grossSalary)) {
            netSalary = grossSalary.subtract(taxes);
        } else {
            netSalary = grossSalary;
        }

        return netSalary;
    }

    private boolean taxedSalaryIsGreaterThanMinimumSalary(BigDecimal taxedSalary) {
        return taxedSalary.compareTo(minimumSalary) == 1;
    }
}

EmployeeDAO is a classical service that is in charge of retrieving information from a persistence storage and it will look like this more or less.

package com.marco.springmockito;
import java.math.BigDecimal;
import org.springframework.stereotype.Component;
@Component
public class EmployeeDAO {

    public BigDecimal getAnnualSalary(long employeeId) {
        // conncetTODB
        // run select for employeeId;
        return new BigDecimal(70000);
    }
}

TaxCalculator will need a TaxDao to retrieve taxes information and it will then operate some sort of boring and long calculation in order to return the taxes.

package com.marco.springmockito;
import java.math.BigDecimal;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class TaxCalculator {

    @Autowired
    private TaxDao taxDao;

    public BigDecimal calculateTaxes(BigDecimal salary) {
        BigDecimal result = salary.multiply(taxDao.getTaxPercentageForYear(2014));
        // some other weird calculation ....
        return result;
    }
}

Now, we want to unit test the SalaryService class. We should not to be bothered by DAOs and databases setup of any sort. In this UNIT test, we don’t care here what the TaxCalculator is doing.

What we want is to test that our SalaryService is behaving as expected and that it is able to correctly use the work of its collaborators.

Here is how we do it with Mockito. We mark the class we want to test with @InjectMocks and we mark with @Mock all of its collaborators ( or @Spy if you need a real implementation ).

Lastly we need to tell our Unit framework, to operate the required Mockito injections before starting the test and we do this with
MockitoAnnotations. initMocks (this);.

In the test we need to mock the expected operations so that we can concentrate on the actual logic we want to test inside the SalaryService .

package com.marco.springmockito;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.when;
import java.math.BigDecimal;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
public class SalaryServiceTest {

    private static final long UserId = 123l;

    @InjectMocks
    private SalaryService salaryService;

    @Mock
    private EmployeeDAO employeeDAO;

    @Mock
    private TaxCalculator taxCalculator;

    @Before
    public void init() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void testMinimumSalary() {
        BigDecimal annualSalary = new BigDecimal(10000);
        when(employeeDAO.getAnnualSalary(UserId)).thenReturn(annualSalary);
        when(taxCalculator.calculateTaxes(annualSalary)).thenReturn(new BigDecimal(1000));
        BigDecimal actual = salaryService.getNetSalary(UserId);
        assertThat(actual.compareTo(new BigDecimal(10000)), is(0));
    }

    @Test
    public void testMaximumSalary() {
        BigDecimal annualSalary = new BigDecimal(80000);
        when(employeeDAO.getAnnualSalary(UserId)).thenReturn(annualSalary);
        when(taxCalculator.calculateTaxes(annualSalary)).thenReturn(new BigDecimal(8000));
        BigDecimal actual = salaryService.getNetSalary(UserId);
        assertThat(actual.compareTo(new BigDecimal(72000)), is(0));
    }
}

It is simple and efficient and hopefully it will be useful for someone else out there.
 

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

JPA Mini Book

Learn how to leverage the power of JPA in order to create robust and flexible Java applications. With this Mini Book, you will get introduced to JPA and smoothly transition to more advanced concepts.

JVM Troubleshooting Guide

The Java virtual machine is really the foundation of any Java EE platform. Learn how to master it with this advanced guide!

Given email address is already subscribed, thank you!
Oops. Something went wrong. Please try again later.
Please provide a valid email address.
Thank you, your sign-up request was successful! Please check your e-mail inbox.
Please complete the CAPTCHA.
Please fill in the required fields.

3 Responses to "Testing Spring components with Mockito"

  1. Rishi Chopra says:

    Nice Article.

  2. Armin says:

    If you use @RunWith annotation at class head and use MockitoJUnitRunner, it is possible to delete the @Before method with containing mock init.

Leave a Reply


eight × = 48



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy | Contact
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.
Do you want to know how to develop your skillset and become a ...
Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

Get ready to Rock!
You can download the complementary eBooks using the links below:
Close