无法启动spring-data-rest单元测试,RepositoryRestResource不能用于@Autowire

时间:2016-11-15 16:44:40

标签: unit-testing junit spring-boot spring-data-rest spring-java-config

我将应用程序从JDBC / REST移植到spring-data-rest并且我的唯一单元测试失败并显示错误

NoSuchBeanDefinitionException: 
    No qualifying bean of type 'com.xxx.repository.ForecastRepository' available

该应用程序之前刚刚使用spring-boot进行了改编,现在我尝试在spring-data-rest之上添加spring-data-jpa新图层。

我试图根据

计算出正确的Java配置

Custom Test Slice with Spring Boot 1.4

但我不得不偏离惯用法,因为

  1. @WebMvcTest注释没有抑制导致测试失败的安全模块
  2. @MockMvcAutoConfiguration由于缺少依赖项而失败,除非我指定@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)(请参阅here
  3. @WebMvcTest@SpringBootTest是互斥的,因为它们都指定了@BootstrapWith并且无法一起运行
  4. 所以这是我最接近的,但Spring无法找到我的@RepositoryRestResource存储库:

    存储库

    @RepositoryRestResource(collectionResourceRel = "forecasts", path = "forecasts")
    public interface ForecastRepository extends CrudRepository<ForecastExEncoded,
            Long> {
    

    JUnit测试

    @RunWith(SpringRunner.class)
    @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK,
            classes = {TestRestConfiguration.class})
    public class ForecastRestTests {
    
        @Autowired
        private MockMvc mockMvc;
    
        @Autowired
        private ForecastRepository forecastRepository;
    
        @Before
        public void deleteAllBeforeTests() throws Exception {
            forecastRepository.deleteAll();
        }
    
        @Test
        public void shouldReturnRepositoryIndex() throws Exception {
    
            mockMvc.perform(get("/")).andDo(print()).andExpect(status().isOk()).andExpect(
                    jsonPath("$._links.forecasts").exists());
        }
    
    }
    

    配置

    @OverrideAutoConfiguration(enabled = false)
    @ImportAutoConfiguration(value = {
            RepositoryRestMvcAutoConfiguration.class,
            HttpMessageConvertersAutoConfiguration.class,
            WebMvcAutoConfiguration.class,
            MockMvcAutoConfiguration.class,
            MockMvcSecurityAutoConfiguration.class
    })
    @Import({PropertySpringConfig.class})
    public class TestRestConfiguration {}
    

    还试过......

    我尝试仅使用@WebMvcTest以及How to exclude AutoConfiguration from Spring Boot下面的@ComponentScan来配置单元测试,以试图简化所有内容,但是excludeFilters没有效果。

    @ComponentScan(
            basePackages="com.xxx",
            excludeFilters = {
                    @ComponentScan.Filter(type = ASSIGNABLE_TYPE,
                            value = {
                                    SpringBootWebApplication.class,
                                    JpaDataConfiguration.class,
                                    SecurityConfig.class
                            })
            })
    

    我已将Spring的日志记录设置为跟踪,因为此时我所能做的就是尝试找到有关日志输出发生情况的线索。到目前为止虽然没有运气。

    我可以在日志记录中看到RepositoryRestConfiguration正在加载,但显然它没有提供正确的信息,我无法弄清楚如何完成这项工作,谷歌搜索和倾注春天docs和API。我想我必须在这里阅读所有相关问题。

    更新2016-11-16 10:00

    我在日志中看到的有关我的一件事是:

    Performing dependency injection for test context  [DefaultTestContext@2b4a2ec7 [snip...]
     classes = '{class com.xxx.TestRestConfiguration, 
        class com.xxx.TestRestConfiguration}', 
    

    即。上下文列出配置类 两次 。我在@SpringBootTest#classes注释上指定了配置类(仅一次)。但是如果我从注释中省略#classes,Spring Boot会通过@SpringBootApplication类找到并拉入所有配置。

    那是一个提示我在错误的地方指定配置吗?我怎么办呢?

1 个答案:

答案 0 :(得分:1)

经过太多时间,我决定采用这种方法。

Custom Test Slice with Spring Boot 1.4看起来很有希望,但我无法随心所欲。

一遍又一遍

Accessing JPA Data with REST

我意识到我必须包含JPA设置,因为spring-data-rest直接使用它们 - 没有机会模拟它们或没有嵌入式数据库运行单元测试。

至少不是我理解的。也许有可能模仿它们并让spring-data-rest针对测试数据运行模拟,但我认为spring-data-restspring-data可能过于紧密耦合。

因此必须进行集成测试。

在随上述文章提供的Spring源代码中

gs-accessing-data-rest/ApplicationTests.java

日志记录显示Spring Boot引入了应用程序上下文的整个配置。

为了避免我的SpringBootApplication类并且没有加载安全模块,我设置了这样的测试:

@RunWith(SpringRunner.class)
@SpringBootTest
@ContextConfiguration(classes = {
        JpaDataConfiguration.class,
        TestJpaConfiguration.class,
        TestRestConfiguration.class,
        PropertySpringConfig.class})
public class ForecastRestTests {

    @SuppressWarnings("SpringJavaAutowiringInspection")
    @Autowired
    private MockMvc mockMvc;

    @Autowired
    private ForecastRepository forecastRepository;

    @Before
    public void deleteAllBeforeTests() throws Exception {
        forecastRepository.deleteAll();
    }

    @Test
    public void shouldReturnRepositoryIndex() throws Exception {

        mockMvc.perform(get("/")).andDo(print()).andExpect(status().isOk()).andExpect(
                jsonPath("$._links.forecasts").exists());
    }

}

使用这些配置类:

@Configuration
@EnableJpaRepositories(basePackages = {"com.bp.gis.tardis.repository"})
@EntityScan(basePackages = {"com.bp.gis.tardis.type"})
public class JpaDataConfiguration {

@Configuration
@OverrideAutoConfiguration(enabled = false)
@ImportAutoConfiguration(value = {
        CacheAutoConfiguration.class,
        JpaRepositoriesAutoConfiguration.class,
        DataSourceAutoConfiguration.class,
        DataSourceTransactionManagerAutoConfiguration.class,
        HibernateJpaAutoConfiguration.class,
        TransactionAutoConfiguration.class,
        TestDatabaseAutoConfiguration.class,
        TestEntityManagerAutoConfiguration.class })
public class TestJpaConfiguration {}

@Configuration
@OverrideAutoConfiguration(enabled = false)
@ImportAutoConfiguration(value = {
        RepositoryRestMvcAutoConfiguration.class,
        HttpMessageConvertersAutoConfiguration.class,
        WebMvcAutoConfiguration.class,
        MockMvcAutoConfiguration.class,
        MockMvcSecurityAutoConfiguration.class
})
public class TestRestConfiguration {}

所以TL; DR摘要是:使用@ContextConfiguration指定指定@OverrideAutoConfiguration@ImportAutoConfiguration

的配置文件