6

I have a multi-module Spring-Boot project. I was wondering how I can set up integration testing just to test Spring Data JPA repositories? The following approach fails with this exception: HV000183: Unable to load 'javax.el.ExpressionFactory'. Check that you have the EL dependencies on the classpath.

Since this module does not depend on the web module, there is no web application that can be started.

@RunWith(SpringJUnit4ClassRunner.class)
@IntegrationTest
@SpringApplicationConfiguration(classes = TestConfiguration.class)
class CardInfoRepositoryIT {

    @Autowired CardInfoRepository cardInfoRepository;

    @Test
    void testLoadData() {
        assert cardInfoRepository.findAll().size() == 1
    }

}
led
  • 541
  • 3
  • 10
  • 18
  • You should use your application class in the `SpringApplicationConfiguration` annotation not some arbitrary configuration you created. Also do you really need the `@Integrationtest`? As that will start your application so that you can use a `RestTemplate` or whatever to test your application. This is not what you seem to be doing or need. – M. Deinum Jan 24 '15 at 12:06
  • 1) I can't use my application class as this module does dot depend on web module (web module contains the application class). 2) Why do I need RestTemplate to test repositories? This is not a web or web-service integration test. – led Jan 24 '15 at 14:32
  • Do you actually understand what `@IntegrationTest` does? Judging from what you are trying to do it has nothing to do with an integration test, in the sense of Spring Boot. You are just writing a unit test for a repository, not an integration test. – M. Deinum Jan 24 '15 at 14:57
  • Trying to access the database and run some queries against it is not a unit test. – led Jan 24 '15 at 18:39
  • In my book that isn't an integration test either, but we can argue about that for a very long time. Your test remains not an integration test in the sense of what the `@IntegrationTest` is for. So remove it, it also doesn't make sense to use the `@SpringApplicationConfiguration` as you aren't passing an application class but just a mere configuration. Hence it is just a plain spring based test. – M. Deinum Jan 24 '15 at 18:53
  • If I remove all those, how do you suggest that I get access to database? I dont want to use xml or java based config. I'd like to use spring boot as much as possible as it makes everything easier. – led Jan 24 '15 at 19:11

2 Answers2

19

As Marten mentioned, @IntegrationTest should only be used when you need to test against the deployed Spring Boot application (e.g., deployed in an embedded Tomcat, Jetty, or Undertow container). So if your goal is to test your repository layer in isolation, you should not use @IntegrationTest.

On the other hand, if your tests require specific Spring Boot functionality (in contrast to standard Spring Framework functionality, semantics, and defaults), then you will in fact want to annotate your test class with @SpringApplicationConfiguration instead of @ContextConfiguration. The reason is that @SpringApplicationConfiguration preconfigures the SpringApplicationContextLoader which is specific to Spring Boot.

Furthermore, if you want your repository layer integration tests to run faster (i.e., without the full overhead of Spring Boot), you may choose to exclude configuration classes annotated with @EnableAutoConfiguration since that will auto-configure every candidate for auto-configuration found in the classpath. So, for example, if you just want to have Spring Boot auto-configure an embedded database and Spring Data JPA (with Hibernate as the JPA provider) along with entity scanning, you could compose your test configuration something like this:

@Configuration
@EnableJpaRepositories(basePackageClasses = UserRepository.class)
@EntityScan(basePackageClasses = User.class)
@Import({ DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class })
public class TestRepositoryConfig {}

And then use that configuration in your test class like this:

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = TestRepositoryConfig.class)
@Transactional
public class UserRepositoryTests { /* ... */ }

Regards,

Sam

p.s. You might find my answer to the following, related question useful as well: Disable security for unit tests with spring boot

Community
  • 1
  • 1
Sam Brannen
  • 24,249
  • 2
  • 75
  • 114
  • Thanks for the detailed explanation. This is what I wanted to know in the first place. – led Jan 25 '15 at 21:32
0

I resolved this by having the following test config class.

@Configuration
@EnableAutoConfiguration
@ComponentScan
@PropertySource("classpath:core.properties")
class TestConfiguration {
}

core.properties is also used by the main application and it contains datasource information. @IntegrationTest annotation can be removed on the test class.

I also added the following to the module as dependencies:

testRuntime 'javax.el:javax.el-api:2.2.4'
testRuntime 'org.glassfish.web:javax.el:2.2.4'
led
  • 541
  • 3
  • 10
  • 18