14

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;
   }
3
  • Are your datasources configured via auto-configuration? Commented Mar 29, 2018 at 15:13
  • @wjans No, its' a bean in the main config. See my edit. Commented Mar 29, 2018 at 15:34
  • 3
    Can't you simply add the datasource as a @MockBean DataSource dataSource too then? Think it has the advantage that your production code doing the JNDI lookup won't even be executed. Commented Mar 30, 2018 at 9:02

2 Answers 2

12

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

Sign up to request clarification or add additional context in comments.

2 Comments

This is my way of doing it too. You can add the MockBean to the TestConfig.class to minimize code duplication aswell.
great suggestion, worked with adding @MockBean(name = "your bean name") in test class
9

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.

4 Comments

Very convenient, thanks. After adding a TestConfiguration in the log I get: Overriding bean definition for bean 'dataSource' with a different definition. I also created another TestConfiguration defining a real datasource, for the integration tests.
Doesn't this have a potential risk that the overriding will happen in a different order? Think it's not a good idea to rely on this, think you should give the mocked bean a different name and annotate it with @Primary to be sure. Still has the disadvantage that both beans will be created though.
I agree with @wjans
Hi, after try your solution, in my case I got the error of BeanCreationException: Error creating bean with name 'entityManagerFactory' defined in class path resource [org/springframework/boot/autoconfigure/orm/jpa/HibernateJpaConfiguration.class]: Invocation of init method failed; nested exception is org.hibernate.service.spi.ServiceException: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment] Do you have any ideas?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.