java - starter - Obtener "Al menos un metamodelo JPA debe estar presente" con @WebMvcTest
spring test (4)
Soy bastante nuevo en Spring e intento hacer algunas pruebas de integración básicas para un @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());
}
}
pero me estoy poniendo
java.lang.IllegalStateException: Failed to load ApplicationContext Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name ''jpaMappingContext'': Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: At least one JPA metamodel must be present! Caused by: java.lang.IllegalArgumentException: At least one JPA metamodel must be present!
A diferencia de la mayoría de las personas que publican este error, no quiero usar JPA para esto. ¿Estoy tratando de usar @WebMvcTest
incorrectamente? ¿Cómo puedo rastrear la magia de primavera que invita a JPA a esta fiesta?
Alternativamente, puede definir una clase de configuración personalizada dentro de su caso de prueba, incluyendo solo el controlador (más sus dependencias), para forzar a Spring a usar este contexto.
Tenga en cuenta que aún tendrá acceso a MockMvc
y otras bondades en su caso de prueba, si está anotado en 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 {}
Elimine cualquier @EnableJpaRepositories
o @EntityScan
de su clase SpringBootApplication
lugar de hacer esto:
package com.tdk;
@SpringBootApplication
@Import({ApplicationConfig.class })
public class TdkApplication {
public static void main(String[] args) {
SpringApplication.run(TdkApplication.class, args);
}
}
Y ponerlo en una clase de configuración separada:
package com.tdk.config;
@Configuration
@EnableJpaRepositories(basePackages = "com.tdk.repositories")
@EntityScan(basePackages = "com.tdk.domain")
@EnableTransactionManagement
public class ApplicationConfig {
}
Y aquí las pruebas:
@RunWith(SpringRunner.class)
@WebAppConfiguration
@WebMvcTest
public class MockMvcTests {
}
Si alguien utiliza Spring Boot y no desea eliminar @EntityScan
y @EnableJpaRepositories
, puede eliminar la anotación @WebMvcTest
de su clase de prueba y agregar lo siguiente:
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
public class DemoControllerIntegrationTests {
@Autowired
private MockMvc mvc;
//...
}
y podrás autowire MockMvc
y usarlo.
Yo tuve el mismo problema. @WebMvcTest busca una clase anotada con @SpringBootApplication (en el mismo directorio o superior en la estructura de la aplicación si no encuentra una). Puedes leer cómo funciona esto en https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-testing-spring-boot-applications-testing-autoconfigured-mvc-tests .
Si su clase anotada con @SpringBootApplication también tiene @EntityScan / @ EnableJpaRepositories, se produce este error. Porque tienes estas anotaciones con @SpringBootApplication y te estás burlando del servicio (por lo que en realidad no estás usando ninguna JPA). He encontrado una solución que puede no ser la más bonita, pero funciona para mí.
Coloque esta clase en su directorio de prueba (la raíz). @WebMvcTest encontrará esta clase antes de su clase de aplicación real. En esta clase no tiene que agregar @ EnableJpaRepositories / @ EntityScan.
@SpringBootApplication(scanBasePackageClasses = {
xxx.service.PackageMarker.class,
xxx.web.PackageMarker.class
})
public class Application {
}
Y tu prueba se verá igual.
@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
}
}
¡Espero que esto ayude!