How to test Spring Data repositories?

前端 未结 8 1773
隐瞒了意图╮
隐瞒了意图╮ 2020-11-29 15:41

I want a repository (say, UserRepository) created with the help of Spring Data. I am new to spring-data (but not to spring) and I use this tutorial. My choice o

相关标签:
8条回答
  • 2020-11-29 15:41

    In the last version of spring boot 2.1.1.RELEASE, it is simple as :

    @RunWith(SpringRunner.class)
    @SpringBootTest(classes = SampleApplication.class)
    public class CustomerRepositoryIntegrationTest {
    
        @Autowired
        CustomerRepository repository;
    
        @Test
        public void myTest() throws Exception {
    
            Customer customer = new Customer();
            customer.setId(100l);
            customer.setFirstName("John");
            customer.setLastName("Wick");
    
            repository.save(customer);
    
            List<?> queryResult = repository.findByLastName("Wick");
    
            assertFalse(queryResult.isEmpty());
            assertNotNull(queryResult.get(0));
        }
    }
    

    Complete code:

    https://github.com/jrichardsz/spring-boot-templates/blob/master/003-hql-database-with-integration-test/src/test/java/test/CustomerRepositoryIntegrationTest.java

    0 讨论(0)
  • 2020-11-29 15:42

    When you really want to write an i-test for a spring data repository you can do it like this:

    @RunWith(SpringRunner.class)
    @DataJpaTest
    @EnableJpaRepositories(basePackageClasses = WebBookingRepository.class)
    @EntityScan(basePackageClasses = WebBooking.class)
    public class WebBookingRepositoryIntegrationTest {
    
        @Autowired
        private WebBookingRepository repository;
    
        @Test
        public void testSaveAndFindAll() {
            WebBooking webBooking = new WebBooking();
            webBooking.setUuid("some uuid");
            webBooking.setItems(Arrays.asList(new WebBookingItem()));
            repository.save(webBooking);
    
            Iterable<WebBooking> findAll = repository.findAll();
    
            assertThat(findAll).hasSize(1);
            webBooking.setId(1L);
            assertThat(findAll).containsOnly(webBooking);
        }
    }
    

    To follow this example you have to use these dependencies:

    <dependency>
        <groupId>com.h2database</groupId>
        <artifactId>h2</artifactId>
        <version>1.4.197</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.assertj</groupId>
        <artifactId>assertj-core</artifactId>
        <version>3.9.1</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-jpa</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
    
    0 讨论(0)
  • 2020-11-29 15:43

    This may come a bit too late, but I have written something for this very purpose. My library will mock out the basic crud repository methods for you as well as interpret most of the functionalities of your query methods. You will have to inject functionalities for your own native queries, but the rest are done for you.

    Take a look:

    https://github.com/mmnaseri/spring-data-mock

    UPDATE

    This is now in Maven central and in pretty good shape.

    0 讨论(0)
  • 2020-11-29 15:48

    I solved this by using this way -

        @RunWith(SpringRunner.class)
        @EnableJpaRepositories(basePackages={"com.path.repositories"})
        @EntityScan(basePackages={"com.model"})
        @TestPropertySource("classpath:application.properties")
        @ContextConfiguration(classes = {ApiTestConfig.class,SaveActionsServiceImpl.class})
        public class SaveCriticalProcedureTest {
    
            @Autowired
            private SaveActionsService saveActionsService;
            .......
            .......
    }
    
    0 讨论(0)
  • 2020-11-29 15:54

    tl;dr

    To make it short - there's no way to unit test Spring Data JPA repositories reasonably for a simple reason: it's way to cumbersome to mock all the parts of the JPA API we invoke to bootstrap the repositories. Unit tests don't make too much sense here anyway, as you're usually not writing any implementation code yourself (see the below paragraph on custom implementations) so that integration testing is the most reasonable approach.

    Details

    We do quite a lot of upfront validation and setup to make sure you can only bootstrap an app that has no invalid derived queries etc.

    • We create and cache CriteriaQuery instances for derived queries to make sure the query methods do not contain any typos. This requires working with the Criteria API as well as the meta.model.
    • We verify manually defined queries by asking the EntityManager to create a Query instance for those (which effectively triggers query syntax validation).
    • We inspect the Metamodel for meta-data about the domain types handled to prepare is-new checks etc.

    All stuff that you'd probably defer in a hand-written repository which might cause the application to break at runtime (due to invalid queries etc.).

    If you think about it, there's no code you write for your repositories, so there's no need to write any unittests. There's simply no need to as you can rely on our test base to catch basic bugs (if you still happen to run into one, feel free to raise a ticket). However, there's definitely need for integration tests to test two aspects of your persistence layer as they are the aspects that related to your domain:

    • entity mappings
    • query semantics (syntax is verified on each bootstrap attempt anyway).

    Integration tests

    This is usually done by using an in-memory database and test cases that bootstrap a Spring ApplicationContext usually through the test context framework (as you already do), pre-populate the database (by inserting object instances through the EntityManager or repo, or via a plain SQL file) and then execute the query methods to verify the outcome of them.

    Testing custom implementations

    Custom implementation parts of the repository are written in a way that they don't have to know about Spring Data JPA. They are plain Spring beans that get an EntityManager injected. You might of course wanna try to mock the interactions with it but to be honest, unit-testing the JPA has not been a too pleasant experience for us as well as it works with quite a lot of indirections (EntityManager -> CriteriaBuilder, CriteriaQuery etc.) so that you end up with mocks returning mocks and so on.

    0 讨论(0)
  • 2020-11-29 15:57

    With JUnit5 and @DataJpaTest test will look like (kotlin code):

    @DataJpaTest
    @ExtendWith(value = [SpringExtension::class])
    class ActivityJpaTest {
    
        @Autowired
        lateinit var entityManager: TestEntityManager
    
        @Autowired
        lateinit var myEntityRepository: MyEntityRepository
    
        @Test
        fun shouldSaveEntity() {
            // when
            val savedEntity = myEntityRepository.save(MyEntity(1, "test")
    
            // then 
            Assertions.assertNotNull(entityManager.find(MyEntity::class.java, savedEntity.id))
        }
    }
    

    You could use TestEntityManager from org.springframework.boot.test.autoconfigure.orm.jpa.TestEntityManager package in order to validate entity state.

    0 讨论(0)
提交回复
热议问题