4

I have a unit test that includes a couple of simple operations with a database. Interaction with database is implemented with Spring Data and JPA. My environment is Spring Boot 1.4.

My test looks like:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(initializers = ConfigFileApplicationContextInitializer.class)
@SpringBootTest(classes = {Application.class})
@Transactional
public class OrderRepositoryTest {
    @Autowired
    private OrderRepository orderRepository;

    @Autowired
    EntityManager entityManager;

    @Test
    public void can_create_and_find_one_order() {
        String orderId = "XX_YY";

        Order order1 = createAnOrder();
        orderRepository.save(order1);

        entityManager.flush();
        entityManager.clear();

        Order order2 = orderRepository.findOne(orderId);
        Assertions.assertThat(order2).isEqualTo(order1);
    }
}

Where Application is the Spring Boot entry point, and contains the EnableAutoConfiguration annotation:

@EnableAutoConfiguration
@EnableConfigurationProperties
@ComponentScan(basePackageClasses = {
    WebMvcConfig.class, 
    ServicesConfiguration.class, 
    WebSecurityConfiguration.class
})
public class Application extends SpringBootServletInitializer {
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder applicationBuilder) {
        return applicationBuilder.sources(Application .class);
    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

The test does load the JPA layer, and performs the operation. But it also loads the MVC configuration, the security configuration, and plenty of other layers that I'm not testing.

Question: How could I replace the EnableAutoConfiguration and load only the JPA layer that I need?

Ideally, it would a configuration class similar to extending ´WebMvcConfigurerAdapter´ in a way that I can use it from the unit test and the application entry point, so my unit test also validates the configuration:

@Configuration
@EnableJpaRepositories(basePackages = "class.path.to.my.repositories")
public class PersistenceConfiguration {
    // Whatever needs to be here
    // ...
}

3 Answers 3

1

If you just want to test the JPA layer, only the @DataJpaTest is need, it will configure an in-memory embedded database, scan for @Entity classes and configure Spring Data JPA repositories. Regular @Component beans will not be loaded into the ApplicationContext.

For example:

@RunWith(SpringRunner.class)
@DataJpaTest
@Transactional
public class SpringBootJPATest {

    @Autowired
    private BlogEntryRepository blogEntryRepository;

    @Autowired
    private TestEntityManager entityManager;

    @Test
    public void jpa_test() {
        BlogEntry entity = new BlogEntry();
        entity.setTitle("Test Spring Boot JPA Test");
        BlogEntry persist = entityManager.persist(entity);
        System.out.println(persist.getId());
    }

    @Test
    public void jap_test_repo() {
        BlogEntry entity = new BlogEntry();
        entity.setTitle("Test Spring Boot JPA Test");
        BlogEntry persist = blogEntryRepository.save(entity);
        System.out.println(persist.getId());
    }
}

The BlogEntryRepository is just an empty interface which extends the JpaRepository

The output( I deleted other info log just leave all Hibernate logs ):

Hibernate: drop table blog_entry if exists
Hibernate: drop table comment if exists
Hibernate: create table blog_entry (id bigint generated by default as identity, content varchar(255), created_on timestamp, title varchar(255), updated_on timestamp, primary key (id))
Hibernate: create table comment (id bigint generated by default as identity, comment varchar(255), blog_entry_id bigint, primary key (id))
Hibernate: alter table comment add constraint FK5f23qjwyt0ffjboqu3go58buu foreign key (blog_entry_id) references blog_entry

......

Hibernate: insert into blog_entry (id, content, created_on, title, updated_on) values (null, ?, ?, ?, ?)
1

......

Hibernate: drop table blog_entry if exists
Hibernate: drop table comment if exists
Sign up to request clarification or add additional context in comments.

4 Comments

Since the original poster apparently wants transactional tests, you should delete (propagation = Propagation.NOT_SUPPORTED) (and rename the test class). Otherwise, your answer looks good.
If I just use this code without any modification, I get the error Unable to find a @SpringBootConfiguration, you need to use @ContextConfiguration or @SpringBootTest(classes=...) with your test
If I add @ContextConfiguration, then I get No configuration classes or locations found in @SpringApplicationConfiguration. For default configuration detection to work you need Spring 4.0.3 or better (found 4.3.2.RELEASE)
@jmgonet Instead of all these annotations just use @SpringBootApplication and make sure its searchable by declaring it in any of the parent packages of your test package
1

As spring-boot document mentioned, use @DataJpaTest is the collect way. Try below code, it works for me.

@RunWith(SpringRunner.class)
@Import(PersistenceConfiguration.class)
@ContextConfiguration(classes = YourOrderRepositoryImpl.class)
@DataJpaTest
@Transactional
public class OrderRepositoryTest {
  @Autowired
  private OrderRepository orderRepository;

  @Autowired
  TestEntityManager entityManager;

  @Test
  public void foo() {
    ...
  }
}

Use @DataJpaTest also need to use @ContextConfiguration to config at lease one spring-manage-bean, otherwise you will get the error Unable to find a @SpringBootConfiguration, you need to use @ContextConfiguration or @SpringBootTest(classes=...) with your test.

And you can use TestEntityManager to instead EntityManager. It's document is also there.

Comments

-1

I would recommend you to use excludeAutoConfiguration in your annotations when you have an undesired configuration for your unit testing. For example, if you don't want JPA or Security config to load automatically in your application context, you can easily exclude them:

@DataJPATest(excludeAutoConfiguration = EmbeddedDataSourceConfiguration.class)

For more info, you can check out this project that has both Integration and Unit tests embedded.

Comments

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.