Getting “At least one JPA metamodel must be present” with @WebMvcTest

前端 未结 5 1290
逝去的感伤
逝去的感伤 2021-02-05 06:02

I\'m fairly new to Spring, trying to do some basic integration tests for a @Controller.

@RunWith(SpringRunner.class)
@WebMvcTest(DemoController.clas         


        
相关标签:
5条回答
  • 2021-02-05 06:06

    Alternatively, you can define a custom configuration class inside your test case, including only the controller (plus its dependencies), to force Spring to use this context.
    Please note, you'll still have access to MockMvc and other goodness in your test case, if it's WebMvcTest annotated.

    @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 讨论(0)
  • 2021-02-05 06:11

    I had the same problem. @WebMvcTest looks for a class annotated with @SpringBootApplication (in the same directory or higher up in your app structure if it doesn't find one). You can read how this works @ https://docs.spring.io/spring-boot/docs/current/reference/htmlsingle/#boot-features-testing-spring-boot-applications-testing-autoconfigured-mvc-tests.

    If your class annotated with @SpringBootApplication also has @EntityScan /@EnableJpaRepositories this error occurs. Because you have these annotations with @SpringBootApplication and you are mocking the service ( so actually not using any JPA ). I found a workaround which may not be the prettiest, but works for me.

    Place this class in your test directory ( the root ). @WebMvcTest will find this class before your actual Application class. In this class you don't have to add @EnableJpaRepositories/@EntityScan.

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

    And your test will look the same.

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

    Hope this helps!

    0 讨论(0)
  • 2021-02-05 06:15

    If anyone uses Spring boot and don't want to remove @EntityScan and @EnableJpaRepositories you can remove @WebMvcTest annotation from your test class and add the following instead:

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

    and you will be able to autowire MockMvc and use it.

    0 讨论(0)
  • 2021-02-05 06:18

    Add @MockBean(JpaMetamodelMappingContext.class) to above of class DemoControllerIntegrationTests:

    @RunWith(SpringRunner.class)
    @WebMvcTest(DemoController.class)
    @MockBean(JpaMetamodelMappingContext.class)
    public class DemoControllerIntegrationTests {
        ...
    }
    

    Because you have not used a database in your test, Spring throws this exception. By mocking JpaMetamodelMappingContext class you will bypass the needed metamodel.

    0 讨论(0)
  • 2021-02-05 06:21

    Remove any @EnableJpaRepositories or @EntityScan from your SpringBootApplication class instead do this:

    package com.tdk;
    
    @SpringBootApplication
    @Import({ApplicationConfig.class })
    public class TdkApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(TdkApplication.class, args);
        }
    }
    

    And put it in a separate config class:

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

    And here the tests:

    @RunWith(SpringRunner.class)
    @WebAppConfiguration
    @WebMvcTest
    public class MockMvcTests {
    
    }
    
    0 讨论(0)
提交回复
热议问题