控制器测试中抛出“至少必须存在一个JPA元模型”

时间:2018-04-04 03:19:48

标签: spring-boot jpa spring-boot-test

我正在尝试测试用@RestController注释的控制器类。我使用的是Spring-Boot 1.5.10

应用程序本身正常启动,但单元测试失败。请记住,我目前只是试图测试控制器(并嘲笑服务 - 我将在稍后测试服务)。

以下是我的一些课程:

Application.java

package com.particles.authservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Import;

@SpringBootApplication
@Import({ ApplicationConfiguration.class })
public class Application {
    public static void main(final String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

ApplicationConfiguration.java

package com.particles.authservice;

import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.data.jpa.convert.threeten.Jsr310JpaConverters;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;

@EntityScan(basePackageClasses = { Application.class, Jsr310JpaConverters.class })
@EnableJpaRepositories
public class ApplicationConfiguration {
}

AccountController.java

package com.particles.authservice.accountservice;

import ...

@RestController
public class AccountController {
    @Autowired
    private AccountService accountService;

    /**
     * This method attempts to login a user and issue a token if the login was successful.
     * <p>
     * If login fails due a login attempt with a non-existent username or an invalid password, an exception is thrown.
     * 
     * @param credentials
     *            ({@link Credentials}) credentials in a JSON-form, that can be unserialized into an object of this type
     * @param response
     *            ({@link HttpServletResponse}) response, which will be sent to the client;
     *            if the credentials were valid the response receives a JWT as an additional header
     * @return ({@link PersistableAccount}) JSON (automatically serialized from the given TO);
     *         if the request was successful, an additional header containing the freshly issued JWT is added into the response
     */
    @RequestMapping(value = "/login", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE)
    public PersistableAccount login(@RequestBody final Credentials credentials, final HttpServletResponse response)
            throws IOException, URISyntaxException {
        final Optional<PersistableAccount> account = accountService.login(credentials);
        if (!account.isPresent()) {
            throw new AccountLoginFailedException(credentials);
        }
        response.setHeader("Token", jwtService.tokenForPersistableAccount(account.get()));
        return account.get();
    }
}

AccountControllerTest.java

package com.particles.authservice;

import static ...
import ...

@RunWith(SpringRunner.class)
@WebAppConfiguration
@WebMvcTest(AccountController.class)
public class AccountControllerTest {

    @Autowired
    private MockMvc mockMvc;

    @MockBean
    private AccountService accountServiceMock;

    @Test
    public void test() throws Exception {
        final Credentials credentials = TestHelper.createCredentials();
        final Optional<PersistableAccount> account = Optional.of(TestHelper.createPersistableAccount());

        given(accountServiceMock.login(credentials))
                                                    .willReturn(account);

        mockMvc
               .perform(MockMvcRequestBuilders.post("/login").accept(MediaType.APPLICATION_JSON))
               .andExpect(status().isOk());
    }
}

我已将 AccountController 简化为一个端点,并为了简洁起见省略了导入。

测试编译得很好,但每当我运行测试时,我会收到以下(嵌套)异常(缩短 - 如果你需要完整的堆栈跟踪,请告诉我):

Caused by: java.lang.IllegalArgumentException: At least one JPA metamodel must be present!
    at org.springframework.util.Assert.notEmpty(Assert.java:277)
    at org.springframework.data.jpa.mapping.JpaMetamodelMappingContext.<init>(JpaMetamodelMappingContext.java:52)
    at org.springframework.data.jpa.repository.config.JpaMetamodelMappingContextFactoryBean.createInstance(JpaMetamodelMappingContextFactoryBean.java:71)
    at org.springframework.data.jpa.repository.config.JpaMetamodelMappingContextFactoryBean.createInstance(JpaMetamodelMappingContextFactoryBean.java:26)
    at org.springframework.beans.factory.config.AbstractFactoryBean.afterPropertiesSet(AbstractFactoryBean.java:134)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1687)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1624)
    ... 40 more

我已经检查了很多类似的问题,但解决这个问题的常用方法似乎并不适用于我的情况。特别是我尝试了以下内容:

  • 使用spring-boot-starter-data-jpa(因为我开始使用该依赖项后不适用于我),托管版本
  • 由于@EnableJpaRepositories和可能@EntityScan方面的问题,将应用程序与其(JPA相关的)配置分开 - 无效(在Getting "At least one JPA metamodel must be present" with @WebMvcTest的第一次回复之后,但是应用程序仍然很好,测试仍然失败)
  • 我尝试过使用JacksonTester - 事实上我只是想在此刻测试控制器功能 - 无济于事(最终需要上下文)
  • 据我所知,我正在嘲笑实际的服务;所以实际上我没有使用任何JPA元模型,是吗?

删除@EnableJpaRepositories注释可以解决问题,但不幸的是它似乎破坏了我的应用程序。

我做错了什么?

1 个答案:

答案 0 :(得分:1)

添加ContextConfiguration。测试没有看到ApplicationConfiguration,因此没有看到任何实体。

@ContextConfiguration(classes = {ApplicationConfiguration.class})
public class AccountControllerTest { ... }

<强>更新

缺少代码的另一件事是@SpringBootTest。尝试用这个注释测试类。