2016-12-20 15 views
9

Jestem dość nowy w Spring, próbując wykonać podstawowe testy integracyjne dla @Controller.Uzyskiwanie "Przynajmniej jeden metamodel WZP musi być obecny" z @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()); 
    } 
} 

ale jestem coraz

 
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! 

przeciwieństwie do większości ludzi opublikowania tego błędu, nie chcę użyć WZP do tego. Czy próbuję nieprawidłowo użyć @WebMvcTest? Jak mogę wyśledzić magię Wiosny, która zaprasza WZP na tę imprezę?

+0

Witam @ Brad, znalazłeś rozwiązanie? Jestem w tej samej sytuacji. – Artegon

+0

@Artegon naprawdę nie; Grałem z różnymi rzeczami i ostatecznie udało mi się ominąć, ale nie mam jasnego zrozumienia, co było nie tak lub co to naprawiło. Odpowiedź Justina wygląda obiecująco. –

Odpowiedz

4

Miałem ten sam problem. @WebMvcTest szuka klasy z adnotacją @SpringBootApplication (w tym samym katalogu lub wyżej w strukturze aplikacji, jeśli jej nie znajduje). Możesz przeczytać, jak to działa @https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-testing-spring-boot-applications-testing-autoconfigured-mvc-tests.

Jeśli twoja klasa opatrzona komentarzem @SpringBootApplication ma również @EntityScan/@ EnableJpaRepositories, ten błąd występuje. Ponieważ masz adnotacje z @SpringBootApplication i kpisz z usługi (tak naprawdę nie używając JPA). Znalazłem obejście, które nie musi być najładniejsze, ale działa dla mnie.

Umieść tę klasę w katalogu testowym (root). @WebMvcTest znajdzie tę klasę przed aktualną klasą aplikacji. W tej klasie nie musisz dodawać @ EnableJpaRepositories/@ EntityScan.

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

Twój test będzie wyglądał tak samo.

@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 
    } 
} 

Mam nadzieję, że to pomoże!

3

usunąć dowolny @EnableJpaRepositories lub @EntityScan z klasy SpringBootApplication zamiast to zrobić:

package com.tdk; 
@SpringBootApplication 
@Import({SecurityConfig.class }) 
public class TdkApplication { 

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

} 

i umieścić go w osobnej klasie config:

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

} 

a tu badań:

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

Alternatywnie można zdefiniować niestandardową konfigurację klasa uration wewnątrz twojego testu, włączając tylko kontroler (plus jego zależności), by zmusić Spring do użycia tego kontekstu.
Pamiętaj, że nadal będziesz mieć dostęp do MockMvc i innych dobroci w teście testowym, jeśli jest to oznaczone jako 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 {} 
+0

To wygląda na świetne podejście. Jednak gdy go wypróbuję, pojawia się kolejny błąd niezadowalającej zależności od innego RestControllera w tym samym pakiecie. O ile wiem, jedyną relacją jest to, że są w tym samym pakiecie. Jeśli @ComponentScan patrzy tylko na testowaną klasę, w jaki sposób powstaje błąd z niepowiązanej klasy? – Tim

+0

@ Właściwość basePackageClasses komponentu ComponentScan oznacza "wszystkie klasy komponentów w tym pakiecie i wszystkie pakiety podrzędne".Jeśli kontrolery korzystają z tego samego pakietu, możesz użyć filtrów włączania/wykluczania, aby zawęzić zakres. – Mohnish

+0

Alternatywnie, zamiast używać @ComponentScan, możesz także po prostu użyć adnotacji @Configuration, a następnie wewnątrz 'TestConf' dodaj' @Bean public DemoController demoController() {return new DemoController(); } '. Następnie skonfiguruje tylko jeden kontroler. – Tim

Powiązane problemy