Исключение. В Controller-Test должна присутствовать по крайней мере одна метамодель JPA.

Я пытаюсь протестировать класс контроллера с аннотацией @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);
    }
}

Конфигурация приложения.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 (ко мне это не относилось, так как я использовал эту зависимость для начала), управляемая версия
  • Отделение приложения от его (связанной с JPA) конфигурации из-за проблем с @EnableJpaRepositories и, возможно, @EntityScan - безрезультатно (после первого ответа в Получение По крайней мере одна метамодель JPA должна присутствовать с @WebMvcTest, но хотя мое приложение все еще запускается нормально, тест все равно не получится)
  • Я пытался использовать JacksonTester - на самом деле я просто хочу проверить функциональность контроллера в данный момент - тоже безрезультатно (в итоге мне понадобился контекст)
  • Насколько я понимаю, я издеваюсь над реальным сервисом; так что на самом деле я не использую никаких метамоделей JPA, не так ли?

Удаление аннотации @EnableJpaRepositories решает проблему, но, к сожалению, это нарушает работу моего приложения.

Что я делаю неправильно?


person Igor    schedule 04.04.2018    source источник


Ответы (1)


Добавьте конфигурацию контекста. Тест не видел ApplicationConfiguration, следовательно, не видел никакой сущности.

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

Обновление:

Еще одна вещь, которой не хватает в коде, — это @SpringBootTest. Попробуйте аннотировать тестовый класс этим.

person CInvt    schedule 04.04.2018
comment
Спасибо за ответ! К сожалению, это не решило проблему. Вызванное исключение остается прежним :(. - person Igor; 04.04.2018
comment
Спасибо еще раз! Теперь это работает, но я хотел просто протестировать уровень RestController. Я думаю, что мог бы глубже изучить JacksonTester. Вы случайно не знаете, могу ли я проверить контроллер в одиночку, например, имитация базовой службы (служб) без использования @SpringBootTest - person Igor; 04.04.2018
comment
Вы можете заглянуть в MockMvc, чтобы протестировать RestControllers. - person CInvt; 04.04.2018
comment
Я заставил его работать, используя аннотации @RunWith(SpringRunner.class), @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK) и @AutoConfigureMockMvc в тестовом классе. Однако: у меня сложилось впечатление, что базовый h2db все еще запускается, хотя я этого не хочу (поскольку я издеваюсь над соответствующими служебными вызовами). Вы случайно не знаете, как предотвратить запуск базы данных? - person Igor; 05.04.2018
comment
Кажется, что после удаления @EnableJpaRepository мое приложение все еще работает как положено. Однако: теперь тесты работают только с @RunWith(SpringRunner.class) и @WebMvcTest(AccountController.class). Согласно выводу консоли, я вижу, что база данных не инициализируется во время моего теста контроллера (это то, что я хочу), но она инициализируется во время обычного выполнения приложения. - person Igor; 05.04.2018