2016-08-11 3 views
4

Моя цель - перенести приложение Spring Boot, ранее разработанное с Spring Boot 1.3, в новейшую версию Spring Boot 1.4. Приложение состоит из нескольких модулей maven, и только один из них содержит класс, аннотированный с помощью @SpringBootApplication.Требуется ли @WebMvcTest аннотация @SpringBootApplication?

Одна часть миграции заключается в использовании аннотации @WebMvcTest, чтобы эффективно тестировать контроллеры, и здесь возникает проблема.

Рассмотрите example application с страницы загрузки gigub Spring. @WebMvcTest аннотация работает отлично, потому что, насколько я понимаю (после нескольких тестов), в основном пакете аннотируется класс @SpringBootApplication. Обратите внимание, что я придерживаюсь той же концепции, что и в приведенном выше примере для моих собственных тестов @WebMvcTest.

Единственное отличие, которое я вижу в своем приложении, классы контроллера расположены в отдельном модуле maven (без @SpringBootApplication аннотированного класса), но с конфигурациями @Configuration и SpringBootConfiguration. Если я не комментирую какой-либо класс с @SpringBootApplication, я всегда получаю утверждение во время тестирования контроллера. Мое утверждение так же, как когда SampleTestApplication класс в приведенном выше примере изменен, чтобы иметь только @EnableAutoConfiguration и @SpringBootConfiguration аннотаций (@SpringBootApplication нет):

getVehicleWhenRequestingTextShouldReturnMakeAndModel(sample.test.web.UserVehicleControllerTests) Time elapsed: 0.013 sec <<< FAILURE! 
java.lang.AssertionError: Status expected:<200> but was:<404> 
    at org.springframework.test.util.AssertionErrors.fail(AssertionErrors.java:54) 
    at org.springframework.test.util.AssertionErrors.assertEquals(AssertionErrors.java:81) 
    at org.springframework.test.web.servlet.result.StatusResultMatchers$10.match(StatusResultMatchers.java:664) 
    at org.springframework.test.web.servlet.MockMvc$1.andExpect(MockMvc.java:171) 
    at sample.test.web.UserVehicleControllerTests.getVehicleWhenRequestingTextShouldReturnMakeAndModel(UserVehicleControllerTests.java:68) 

Как я должен иметь дело с этим? Должен ли я всегда иметь класс, аннотированный с помощью @SpringBootApplication, чтобы запускать тесты @WebMvcTest?

EDIT 1: Я сделал небольшой проект maven с двумя модулями и минимальной конфигурацией. Это here. Теперь я получаю исключение NoSuchBeanDefinitionException для репозитория, определенного в другом модуле. Если я настрою «полный» @SpringBootApplication - все в порядке.

EDIT 2: Я модифицировал небольшой тестовый проект с EDIT 1, чтобы дать оригинальную проблему. Я играл с разными аннотациями и добавил @ComponentScan в классе конфигурации, потому что я подозревал, что бобовые не зарегистрированы правильно. Тем не менее, я ожидаю, что только @Controller bean (определенный в @WebMvcTest (... class)) должен быть зарегистрирован на основе магии позади поведения @WebMvcTest.

EDIT 3: Spring Boot project issue.

+0

Я получил свой небольшой проект, чтобы пройти тест. Не уверен, что этого достаточно, чтобы ответить на ваш вопрос, или если вам нужно переместить несколько классов, чтобы лучше представлять проблему. –

+1

@ShawnClark, спасибо, что попробовали. Вы добавили '@ SpringBootApplication' в класс конфигурации. Может быть, я не был полностью ясен раньше, но этот трюк также работает для меня. Я ожидаю, что в моем модуле мне не нужно ставить '@ SpringBootApplication'. – tysonite

ответ

1

Короткий ответ: Я так считаю.

Длинный ответ:

Я считаю @WebMvcTest потребности найти конфигурацию SpringBootApplication так WebMvcTest «s единственная цель состоит в том, чтобы помочь упростить тесты (SpringBootApplication скорее будет пытаться загрузить весь мир).

В вашем конкретном случае, так как у вас нет в ваших пакетах без тестирования, я считаю, что он также находит SampleTestConfiguration, который аннотируется @ScanPackages и каким-то образом загружает все бобы.

Добавьте следующее в src/main/java/sample/test

@SpringBootApplication 
public class SampleTestConfiguration { 

} 

И изменить тест на это:

@RunWith(SpringRunner.class) 
@WebMvcTest(MyController.class) 
public class MyControllerTest { 

    @Autowired 
    private MockMvc mvc; 

    @MockBean 
    private MyService ms; 

    @Autowired 
    private ApplicationContext context; 

    @Test 
    public void getDataAndExpectOkStatus() throws Exception { 
     given(ms.execute("1")).willReturn(false); 
     mvc.perform(get("/1/data").accept(MediaType.APPLICATION_JSON_VALUE)).andExpect(status().isOk()).andExpect(content().string("false")); 
    } 

    @Test 
    public void testMyControllerInAppCtx() { 
     assertThat(context.getBean(MyController.class), is(not(nullValue()))); 
    } 

    @Test 
    public void testNoMyAnotherControllerInAppCtx() { 
     try { 
      context.getBean(MyAnotherController.class); 
      fail("Bean exists"); 
     } catch (BeansException e) { 
      // ok 
     } 
    } 
} 

@WebMvcTest находит SpringBootApplication, а затем загрузить только ограниченное количество бобов (см documentation):

@WebMvcTest будет автоматически настраивать инфраструктуру Spring MVC и лимитированные отсканированные бобы до @Controller, @ControllerAdvice, @JsonComponent, Фильтр, WebMvcConfigurer и HandlerMethodArgumentResolver. Обычный @ Компонентные компоненты не будут сканироваться при использовании этой аннотации.

WebMvcTest требует SpringBootApplication: WebMvcTest наследует многие автонастройки, поэтому она нуждается в SpringBoot, чтобы загрузить их. Затем он отключает многие другие функции AutoConfiguration, и ваши контроллеры становятся легко проверяемыми.

Весь смысл использования WebMvcTest, когда у вас есть SpringBootApplication, и вы хотите, чтобы сделать его проще, чтобы проверить, отключив все бобы, кроме контроллеров. Если у вас нет SpringBootApplication, зачем вообще использовать WebMvcTest?

0

Да, в соответствии с алгоритмом spring boot docs

Поиски работы по сравнению с пакетом, который содержит тест до тех пор, пока не найдет @SpringBootApplication или @SpringBootConfiguration аннотированный класса. Пока вы структурируете свой код разумным способом, обычно обнаруживается ваша основная конфигурация.

Но после того, как я использовал @ WebMvcTest, весенний ботинок по-прежнему пытается загрузить другие бобы, наконец TypeExcludeFilter сделал трюк.

`` `ява

@RunWith(SpringRunner.class) 
@WebMvcTest(controllers = {JzYsController.class}) 
public class JzYsControllerTest { 

    private static final String REST_V4_JZYS = "/rest/v4/JzYs"; 

    @Autowired 
    private MockMvc mockMvc; 

    @MockBean 
    private JzYsService service; 

    @Test 
    public void deleteYsByMlbh() throws Exception { 
     Mockito.when(service.deleteYsByMlbh(Mockito.anyString())).thenReturn(Optional.of(1)); 
     mockMvc.perform(delete(REST_V4_JZYS + "?mbbh=861FA4B0E40F5C7FECAF09C150BF3B01")) 
     .andExpect(status().isNoContent()); 
    } 

    @SpringBootConfiguration 
    @ComponentScan(excludeFilters = @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class)) 
    public static class config{ 
    } 
} 

` ``