it-roy-ru.com

Получение "По крайней мере, одна метамодель JPA должна присутствовать" с @WebMvcTest

Я довольно новичок в Spring, пытаюсь выполнить некоторые базовые интеграционные тесты для @Controller.

@RunWith(SpringRunner.class)
@WebMvcTest(DemoController.class)
public class DemoControllerIntegrationTests {
    @Autowired
    private MockMvc mvc;

    @MockBean
    private DemoService demoService;

    @Test
    public void index_shouldBeSuccessful() throws Exception {
        mvc.perform(get("/home").accept(MediaType.TEXT_HTML)).andExpect(status().isOk());
    }
}

но я получаю

 Java.lang.IllegalStateException: Не удалось загрузить ApplicationContext 
 Вызвано: org.springframework.beans.factory.BeanCreationException: Ошибка создания компонента с именем «jpaMappingContext»: сбой вызова метода init; вложенным исключением является Java.lang.IllegalArgumentException: должна присутствовать хотя бы одна метамодель JPA! 
 Вызывается: Java.lang.IllegalArgumentException: должна присутствовать хотя бы одна метамодель JPA! 

В отличие от большинства людей, публикующих эту ошибку, я не хочу использовать JPA для этого. Я пытаюсь использовать @WebMvcTest неправильно? Как я могу отследить магию Весны, которая приглашает JPA на эту вечеринку?

18
Brad Mace

Удалите все @EnableJpaRepositories или @EntityScan из вашего класса SpringBootApplication, вместо этого сделайте следующее:

package com.tdk;

@SpringBootApplication
@Import({ApplicationConfig.class })
public class TdkApplication {

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

И поместите его в отдельный класс конфигурации: 

package com.tdk.config;

@Configuration
@EnableJpaRepositories(basePackages = "com.tdk.repositories")
@EntityScan(basePackages = "com.tdk.domain")
@EnableTransactionManagement
public class ApplicationConfig {

}

А вот и тесты:

@RunWith(SpringRunner.class)
@WebAppConfiguration
@WebMvcTest
public class MockMvcTests {

}
13
Nuñito de la Calzada

Кроме того, вы можете определить собственный класс конфигурации внутри вашего тестового примера, включая только контроллер (плюс его зависимости), чтобы заставить Spring использовать this context.
Обратите внимание, что вы по-прежнему будете иметь доступ к MockMvc и другим качествам в вашем тестовом примере, если он WebMvcTest аннотирован.

@RunWith(SpringRunner.class)
@WebMvcTest(DemoController.class)
public class DemoControllerIntegrationTests {
    @Autowired
    private MockMvc mvc;

    @MockBean
    private DemoService demoService;

    @Test
    public void index_shouldBeSuccessful() throws Exception {
        mvc.perform(get("/home").accept(MediaType.TEXT_HTML)).andExpect(status().isOk());
    }

    @Configuration
    @ComponentScan(basePackageClasses = { DemoController.class })
    public static class TestConf {}
4
Mohnish

У меня такая же проблема. @WebMvcTest ищет класс, аннотированный @SpringBootApplication (в том же каталоге или выше в структуре вашего приложения, если он не находит). Вы можете прочитать, как это работает @ https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-testing-spring-boot-applications-testing-autoconfigured-mvc- тесты .

Если ваш класс, аннотированный @SpringBootApplication, также имеет @EntityScan/@ EnableJpaRepositories, эта ошибка возникает. Потому что у вас есть эти аннотации с @SpringBootApplication, и вы издеваетесь над сервисом (поэтому на самом деле не используете JPA). Я нашел обходной путь, который, возможно, не самый красивый, но работает для меня. 

Поместите этот класс в свой тестовый каталог (корень). @WebMvcTest найдет этот класс до вашего фактического класса Application. В этом классе вам не нужно добавлять @ EnableJpaRepositories/@ EntityScan.

@SpringBootApplication(scanBasePackageClasses = {
    xxx.service.PackageMarker.class,
    xxx.web.PackageMarker.class
})
public class Application {
}

И ваш тест будет выглядеть так же.

@RunWith(SpringRunner.class)
@WebMvcTest
@WithMockUser
public class ControllerIT {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private Service service;

    @Test
    public void testName() throws Exception {
        // when(service.xxx(any(xxx.class))).thenReturn(xxx); 
        // mockMvc.perform(post("/api/xxx")...
        // some assertions
    }
}

Надеюсь это поможет!

4
Justin K

Если кто-то использует загрузку Spring и не хочет удалять @EntityScan и @EnableJpaRepositories, вы можете удалить аннотацию @WebMvcTest из вашего тестового класса и добавить вместо нее следующее:

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
public class DemoControllerIntegrationTests {
    @Autowired
    private MockMvc mvc;

    //...
}

и вы сможете автоматически подключать MockMvc и использовать его.

1
Mis94