Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Boot Datasource in unit tests

I have a simple Spring Boot web app, that reads from a database and return a JSON response. I have the following test configuration:

@RunWith(SpringRunner.class)
@SpringBootTest(classes=MyApplication.class, properties={"spring.config.name=myapp"})
@AutoConfigureMockMvc
public class ControllerTests {
    @Autowired
    private MockMvc mvc;
    @MockBean
    private ProductRepository productRepo;
    @MockBean
    private MonitorRepository monitorRepo;

    @Before
    public void setupMock() {
        Mockito.when(productRepo.findProducts(anyString(), anyString()))
        .thenReturn(Arrays.asList(dummyProduct()));     
    }

    @Test
    public void expectBadRequestWhenNoParamters() throws Exception {    
        mvc.perform(get("/products"))
                .andExpect(status().is(400))
                .andExpect(jsonPath("$.advice.status", is("ERROR")));
    }

    //other tests
}

I have a DataSource bean that is configured in the main configuration of the application. When I run the tests Spring tries to load the context and fails, because the datasource is taken from JNDI. In general I want to avoid creating a datasource for this tests, because I have the repositories mocked.

Is it possible to skip the creation of datasource when running the unit tests?

In memory database for testing is not an option, because my database creation script has a specific structure and cannot be easily executed from classpath:schema.sql

Edit The datasource is defined in MyApplication.class

    @Bean
    DataSource dataSource(DatabaseProeprties databaseProps) throws NamingException {
       DataSource dataSource = null;
       JndiTemplate jndi = new JndiTemplate();
       setJndiEnvironment(databaseProps, jndi);
       try {
           dataSource = jndi.lookup(databaseProps.getName(), DataSource.class);
       } catch (NamingException e) {
           logger.error("Exception loading JNDI datasource", e);
           throw e;
       }
       return dataSource;
   }
like image 982
Evgeni Dimitrov Avatar asked Mar 29 '18 14:03

Evgeni Dimitrov


People also ask

What is DataSource spring boot?

Spring boot datasource configuration is nothing but the factory of connection which was used in a physical data source. Spring boot datasource uses the database credential to set up connections between the database server, it is alternative to the facility of Driver Manager.

What is SpringBootTest?

@SpringBootTest is a primary annotation to create unit and integration tests in Spring Boot applications. The annotation enables additional features such as custom environment properties, different web environment modes, random ports, TestRestTemplate and WebTestClient beans.


2 Answers

Try adding your datasource as a @MockBean too:

@MockBean
private DataSource dataSource

That way Spring will do the replacing logic for you, having the advantage that your production code bean creation won't even be executed (no JNDI lookup).

like image 64
wjans Avatar answered Oct 13 '22 01:10

wjans


Since you are loading configuration class MyApplication.class datasource bean will be created, Try moving datasource in another bean which is not used in a test, make sure all classes loaded for tests are not dependant on datasource.
Or
In your tests create a config class marked with @TestConfiguration and include it in SpringBootTest(classes=TestConfig.class) mocking data source there like

@Bean
public DataSource dataSource() {
    return Mockito.mock(DataSource.class);
}

But this may fail since method call to this mocked datasouce for connection will return null, In that case, you'll have to create an in-memory datasource and then mock jdbcTemplate and rest of dependencies.

like image 25
donm Avatar answered Oct 13 '22 00:10

donm