Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

JUnit testing of Spring MVC application: Testing the Service Layer

DZone's Guide to

JUnit testing of Spring MVC application: Testing the Service Layer

· Java Zone
Free Resource

Learn how to troubleshoot and diagnose some of the most common performance issues in Java today. Brought to you in partnership with AppDynamics.

In continuation of my earlier blogs on Introduction to Spring MVC and Testing DAO layer in Spring MVC, in this blog I will demonstrate how to test Service layer in Spring MVC. The objective of this demo is 2 fold, to build the Service layer using TDD and increase the code coverage during JUnit testing of Service layer.

For people in hurry, get the latest code from Github and run the below command

mvn clean test -Dtest=com.example.bookstore.service.AccountServiceTest

Since in my earlier blog, we have already tested the DAO layer, in this blog we only need to focus on testing service layer. We need to mock the DAO layer so that we can control the behavior in Service layer and cover various scenarios. Mockito is a good framework which is used to mock a method and return known data and assert that in the JUnit.

As a first step we define the AccountServiceTestContextConfiguration class with AccountServiceTest class. If you notice there are 2 beans defined in that class and we marked the as a @Configuration which shows that it is a Spring Context class. In the JUnit test we @Autowired AccountService class. And AccountServiceImpl @Autowired the AccountRepository class. When creating the Bean in the configuration file we also stubbed the AccountRepository class using Mockito,

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class AccountServiceTest {

@Configuration
static class AccountServiceTestContextConfiguration {
@Bean
public AccountService accountService() {
return new AccountServiceImpl();
}
@Bean
public AccountRepository accountRepository() {
return Mockito.mock(AccountRepository.class);
}
}

//We Autowired the AccountService bean so that it is injected from the configuration
@Autowired
private AccountService accountService;
@Autowired
private AccountRepository accountRepository;

During the setup of the JUnit we use Mockito mock findByUsername method to return a predefined account object as below

@Before
public void setup() {
Account account = new AccountBuilder() {
{
address("Herve", "4650", "Rue de la gare", "1", null, "Belgium");
credentials("john", "secret");
name("John", "Doe");
}
}.build(true);
Mockito.when(accountRepository.findByUsername("john")).thenReturn(account);
}

Now we write the tests as below and test both the positive and negative scenarios,

@Test(expected = AuthenticationException.class)
public void testLoginFailure() throws AuthenticationException {
accountService.login("john", "fail");
}
@Test()
public void testLoginSuccess() throws AuthenticationException {
Account account = accountService.login("john", "secret");
assertEquals("John", account.getFirstName());
assertEquals("Doe", account.getLastName());
}
}

Finally we verify if the findByUsername method is called only once successfully as below in the teardown,

@After
public void verify() {
Mockito.verify(accountRepository, VerificationModeFactory.times(1)).findByUsername(Mockito.anyString());
// This is allowed here: using container injected mocks
Mockito.reset(accountRepository);
}

AccountService class looks as below,

@Service
@Transactional(readOnly = true)
public class AccountServiceImpl implements AccountService {

@Autowired
private AccountRepository accountRepository;

@Override
public Account login(String username, String password) throws AuthenticationException {
Account account = this.accountRepository.findByUsername(username, password);
} else {
throw new AuthenticationException("Wrong username/password", "invalid.username");
}
return account;
}
}

I hope this blog helped you. In my next blog, I will demo how to build a controller JUnit test.

Reference:

Pro Spring MVC: With Web Flow by by Marten Deinum, Koen Serneels


 

Understand the needs and benefits around implementing the right monitoring solution for a growing containerized market. Brought to you in partnership with AppDynamics.

Topics:

Published at DZone with permission of Krishna Prasad, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}