25

I am working on a Spring application (Spring 3.0) and following layered architecture i.e. Controller -> Service -> DAO layers.

I want to write unit test cases for service and DAO layer using Junit.
I checked Spring official site and also tried many other sites but couldn't figure out an easy and simple way of doing it.

Can anybody provide me some helpful resources ?


EDIT :
Looks like Mockito is the good option. Any good link to use it in Spring.

Thank you Alex for suggesting it.

Ajinkya
  • 22,324
  • 33
  • 110
  • 161
  • CAREFUL. The link "Mocking service layer" leads now to a malicious page. – Cenobyte321 Feb 21 '17 at 15:51
  • @Cenobyte321 Thanks, link removed. – Ajinkya Feb 22 '17 at 15:43
  • 1
    If you use hibernate and spring boot, why don't configure an H2 in memory database initialized when you start your test ? Then use Annotation SpringBootTest AutoConfigureTestEntityManager Transactional on your test class and just Autowired your dao and you can really test it without mock. Better you can use MockMvc and test your whole webservice from controller ( and so i guess you controller use service which use dao ) – amdev Jun 04 '17 at 23:25

3 Answers3

26

In terms of resources the Spring documentation on testing is very good. This can be found here.

When you test your service layer you will want to use a mocking library such as Mockito to mock your DAOs and therefore your domain layer. This ensures that they are true unit tests.

Then to integration test your DAOs against a database you can use the Spring transactional test utilities described in that reference documentation.

Alex Barnes
  • 7,174
  • 1
  • 30
  • 50
4

Don't know much about resources, but it's not that hard to do if you have your dao + spring setup nicely. You'll need the following:

  1. JUNIT dependencies obivously. with maven, something like that:

    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.8.2</version>
    </dependency>
    
  2. The test class, which you place inside src/test/java:

    @TransactionConfiguration(defaultRollback = true)
    @ContextConfiguration({ "classpath:test-spring-context.xml" })
    @Transactional  
    @RunWith(SpringJUnit4ClassRunner.class)  
    public class SomeTests { 
        // ...
    }
    
  3. The context file for your spring setup referencing your DAO datasource placed inside src/test/resources. Somewhere in your test-spring-context.xml:

    <import resource="datasource-test.xml" />
    

Now for example in eclipse you can run the project as a JUNIT test.

Need more details? Is this solution applicable?

Matsemann
  • 21,083
  • 19
  • 56
  • 89
Pete
  • 10,720
  • 25
  • 94
  • 139
  • Thanks. How can I test service layer ? – Ajinkya Dec 22 '11 at 09:26
  • Not sure what exactly a service is for you but I'm assuming it's supposed to hold application logic, calling CRUD methods on the DAOs whenever the controller tells it to? If so, there's no difference. You just inject the service class in the above setup, call the methods, compare the results and afterwards all will be rolled back. – Pete Dec 22 '11 at 09:32
  • Yes. By service I mean class which invokes DAO methods. – Ajinkya Dec 22 '11 at 09:34
  • 1
    If you really want to unit test the service layer you should mock database access and test just the logic. – Alex Barnes Dec 22 '11 at 09:34
  • You've got a point there.. Might be worth thinking about. We usually use mocked objects in the database to test the services, relying on underlying tests to ensure our DAO is not faulty so in the end it's as if we're working with offline entities. Saves some mocking, but like I said, might have to think about how clean that is.. – Pete Dec 22 '11 at 09:38
  • Yep, so you test your DAOs and Services at the same time. This is how we started off and are now making the transition towards more pure unit tests in the service layer and database backed tests in the domain layer only. – Alex Barnes Dec 22 '11 at 09:41
  • So we discussed this and decided that mocking DAOs to test the service layer is not practical for our data heavy app, reduces flexibility and introduces potential sources for further bugs. – Pete Dec 22 '11 at 10:31
  • I almost ran the same as @Pete said, yet I got `Unable to construct current session context [org.springframework.orm.hibernate4.SpringSessionContext]` , any idea ? – Allan Ruin Mar 24 '14 at 03:38
  • Hello all, I was curious about difference between this two approach. 1.Testsuite class loading Application context. 2. they way @pete said @RunWith(SpringJUni...) If I have say 15 Businesslogic classes which call dao. Which is better and whats difference netween this two approach? – VedantK Nov 22 '15 at 06:32
  • this answer above is integration test right? , not a unit test for dao layer – Vijay Jun 26 '22 at 06:32
0

A DAO unit test (specifically a unit test not an integration test) which uses a Repo can be done like the following code snippet. No need to use things like the following as they are spring integration test-related annotations

@TransactionConfiguration(defaultRollback = true)
@ContextConfiguration({ "classpath:test-spring-context.xml" })

but if you want to test using test db and retrieving from DB you need to use @SpringBootTest and other integration test annotation

public class CrudDaoTest {
    @InjectMocks
    CrudDao crudDao = new CrudDaoImpl();

    @Mock
    DataRepo dataRepo;

    @BeforeEach
    public void init() {
        MockitoAnnotations.openMocks(this);
    }

    @Test
    public void getNamesTest(){
        when(dataRepo.findAll()).thenReturn(new ArrayList<>());
        List<DatEntity> res = crudDao.getNames();
        Assertions.assertNotNull(res);
    }
}
Suraj Rao
  • 29,388
  • 11
  • 94
  • 103
Vijay
  • 151
  • 1
  • 6