Search code examples
javaspringunit-testingspring-bootmockito

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?

Note: 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;
   }

Solution

  • 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.