4
votes

Here is a unit testing class for a java spring data repository layer. I have a spring data repository layer in which the annotation @Autowired is used to inject TestEntityManager type object (belongs to spring data package). The autowiring works whitout adding @RunWith(SpringRunner.class) annotation ! So what is the problem ? Well, I think that injection should not be possible whitout adding @RunWith(SpringRunner.class) annotation to the class : it should not work without it theorically. How is it possible ? Does someone have any answer ?

>>>> view complete spring boot app code on github available here

  • Someone else have had the opposite problem in stackoverflow :

Someone else have had the opposite problem : see link here

Here is my strange bloc of code that amazingly that works :

package org.loiz.demo;

import org.assertj.core.api.BDDAssertions;
import org.junit.Assert;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Test ;
import org.junit.jupiter.api.TestMethodOrder;
import org.junit.jupiter.api.Order ;

import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;

import demo.LoizBootSpringDemoApplication;
import demo.crepository.UserRepositoryInterface;
import demo.dmodel.User;
import demo.helper.helperUtils;

//Test de la couche de persistence
//@RunWith(SpringRunner.class)
@DataJpaTest
@ContextConfiguration(classes = { LoizBootSpringDemoApplication.class})
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@SuppressWarnings("unused")
public class LoizPersistenceTest 
{
    
    @Autowired
    private TestEntityManager testEntityManager;

    @Autowired
    private UserRepositoryInterface repository; 

    private static Long idStub ;
    
    @Test
    @Order(1)
    @Rollback(false)
    @DisplayName("Test de sauvegarde d\'un user \"prenom21 Nom21\"")    
    public void saveShouldMapCorrectly() throws Exception {
        
        User userStub = new User("prenom21", "Nom21");                       
        
        User UserSaved = this.testEntityManager.persistFlushFind(userStub);
        
        BDDAssertions.then(UserSaved.getId()).isNotNull();                    
        idStub = UserSaved.getId() ;
        
        User UserRead = this.testEntityManager.find(User.class, idStub) ;       
        
        BDDAssertions.then(UserSaved.getFirstName()).isNotBlank();
        BDDAssertions.then(UserSaved.getFirstName()).isEqualToIgnoringCase("prenom21");
        

        BDDAssertions.then(UserSaved.getLastName()).isEqualToIgnoringCase("Nom21");
        BDDAssertions.then(UserSaved.getLastName()).isNotBlank();
    }

    @Test
    @Order(2) 
    @DisplayName("Test d'existence du user \"prenom21 Nom21\"") 
    public void readShouldMapCorrectly() throws Exception {
        User userStub = new User(idStub, "prenom21", "Nom21");          
        User userFetched  = this.testEntityManager.find(User.class, idStub) ;
        
        String sUserStub = userStub.toString() ;        
        String sUserFetched = userFetched.toString() ;      
        
        
        boolean bolSameObject = userStub.equals(userFetched) ;
        
        boolean bolAttrEgalEgal = sUserStub == sUserFetched ;       
        
        boolean bolStringEqual = sUserStub.equals(sUserFetched) ;           
        
        boolean bBeanUtil = helperUtils.haveSamePropertyValues (User.class,userStub,userFetched) ;
        
                
        Assert.assertTrue(bBeanUtil);
        
    }

}

Maybe it is normal, but what do i have to know ? I would appreciate some answer please :)

>>>> view complete spring boot app code on github available here

2

2 Answers

2
votes

@RunWith(SpringRunner.class) is used for junit 4 test. But in our case, it is Junit 5 that is used. That is what we can see reading at the pom.xml file (using of junit.jupiter artifact proves that). So @RunWith(SpringRunner.class) has no effects to manage spring container. it should be replaced by @ExtendWith(SpringExtension.class).

HOWEVER :

@DataJpaTest already "contains" @ExtendWith(SpringExtension.class) !!! So we don't need to add @ExtendWith(SpringExtension.class) when @DataJpaTest is used. @DataJpaTest will allow to test spring data repository layer but will also guarantee spring dependency injection. That is to say, and roughly speeking, you can use @Autowired annotation for a class which is annotated @DataJpaTest (a spring data repository layer).

1
votes

From imports junit.jupiter i can see you are using junit-5, were @RunWith belongs to junit-4, and for reference @ExtendWith is not mandataroy for junit-5 test and if you want to use a specific runner you still require the @ExtendsWith but as @DataJpaTest itself is annotated with @ExtendsWith you don't need to do this explicitly

In JUnit 5, the @RunWith annotation has been replaced by the more powerful @ExtendWith annotation.

To use this class, simply annotate a JUnit 4 based test class with @RunWith(SpringJUnit4ClassRunner.class) or @RunWith(SpringRunner.class).