web-dev-qa-db-fra.com

Obtenir "Au moins un métamodèle JPA doit être présent" avec @WebMvcTest

Je suis assez nouveau dans Spring et j'essaie de faire quelques tests d'intégration de base pour 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());
    }
}

mais j'obtiens

 Java.lang.IllegalStateException: Impossible de charger ApplicationContext 
 Causée par: org.springframework.beans.factory.BeanCreationException: Erreur lors de la création d'un bean avec le nom 'jpaMappingContext': L'invocation de la méthode init a échoué; L'exception imbriquée est Java.lang.IllegalArgumentException: au moins un métamodèle JPA doit être présent! !__. Causé par: Java.lang.IllegalArgumentException: au moins un métamodèle JPA doit être présent! 

Contrairement à la plupart des gens qui publient cette erreur, je ne souhaite pas utiliser JPA pour cela. Est-ce que j'essaie d'utiliser @WebMvcTest de manière incorrecte? Comment retrouver la magie du printemps qui invite JPA à cette fête?

18
Brad Mace

Supprimez tout @EnableJpaRepositories ou @EntityScan de votre classe SpringBootApplication à la place, procédez comme suit:

package com.tdk;

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

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

Et mettez-le dans une classe de configuration séparée: 

package com.tdk.config;

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

}

Et voici les tests:

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

}
13

Vous pouvez également définir une classe de configuration personnalisée dans votre scénario de test, comprenant uniquement le contrôleur (ainsi que ses dépendances), afin de forcer Spring à utiliser this context.
Veuillez noter que vous aurez toujours accès à MockMvc et à d'autres bienfaits dans votre scénario de test, si elle est WebMvcTest annotée.

@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

J'ai eu le même problème. @WebMvcTest recherche une classe annotée avec @SpringBootApplication (dans le même répertoire ou plus haut dans la structure de votre application si elle n'en trouve pas). Vous pouvez lire comment cela fonctionne @ https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-testing-spring-boot-applications-testing-autoconfigured-mvc- tests .

Si votre classe annotée avec @SpringBootApplication comporte également @EntityScan/@ EnableJpaRepositories, cette erreur se produit. Parce que vous avez ces annotations avec @SpringBootApplication et que vous vous moquez du service (vous n'utilisez donc aucun JPA). J'ai trouvé une solution de contournement qui n'est peut-être pas la plus jolie, mais qui fonctionne pour moi. 

Placez cette classe dans votre répertoire de test (la racine). @WebMvcTest trouvera cette classe avant votre classe Application actuelle. Dans cette classe, vous n'avez pas besoin d'ajouter @ EnableJpaRepositories/@ EntityScan.

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

Et votre test aura le même aspect.

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

J'espère que cela t'aides!

4
Justin K

Si quelqu'un utilise Spring Boot et ne veut pas supprimer @EntityScan et @EnableJpaRepositories, vous pouvez supprimer l'annotation @WebMvcTest de votre classe de test et ajouter les éléments suivants à la place:

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

    //...
}

et vous serez en mesure d'autowire MockMvc et de l'utiliser.

1
Mis94