Как вызвать сервисный метод Springs из контроллера (Junit)

Я видел пример , как для вызова контроллера Spring с помощью mockito.

Используя Mock, я вызываю контроллер Spring MVC. Контроллер вызывает сервисный класс Spring.

@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(locations = { "file:src/main/webapp/WEB-INF/spring/root-context.xml" })
public class TestController {


    @Mock
    private TestService testService;

    @InjectMocks
    private PaymentTransactionController paymentController;

    private MockMvc mockMvc;


     @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
        this.setMockMvc(MockMvcBuilders.standaloneSetup(paymentController).build());
    }

    @Test
    public void test() throws Exception {
        this.mockMvc.perform(post("/tr/test").content(...)).andExpect(status().isOk());
        // testService.save(); <-- another way
    }

Хорошо, это работает хорошо. Я очень хорошо называю свой контроллер Spring. Но в контроллере Spring у меня есть внедренный сервисный уровень.

@Autowired
private TestService serviceTest;


@RequestMapping(value = "/test", method = RequestMethod.POST)
@ResponseBody()
public String test(HttpServletRequest request) {
   ...
    serviceTest.save(); 
   // in save method I call dao and dao perist data;
   // I have injected dao intrface in serviceTest layer
   ...
   return result;

}

Проблема в том, что мое приложение не вызывает метод сохранения, он не вводится в него. У меня тоже нет ошибки. Тот же результат, когда я вызываю метод save() из Junit (я прокомментировал его в методе test()).

Когда я отлаживаю, я видел, что метод прерывания происходит из org.mockito.internal.creation.MethodInterceptorFilter

Как решить эту проблему? что случается?


person grep    schedule 22.10.2014    source источник
comment
Не могу понять ваш вопрос. Вы издеваетесь над сервисом. Это нормально, что ничего не вызывается, вам нужно просто проверить, что было вызвано...   -  person Serge Ballesta    schedule 22.10.2014
comment
Я хочу вызвать сервисный уровень, чтобы затем проверить, хорошо ли он написан. не так ли?   -  person grep    schedule 22.10.2014
comment
У меня есть MockMVC, потому что я не хотел запускать Tomcat Server.   -  person grep    schedule 22.10.2014


Ответы (3)


Если вы выполняете модульное тестирование своего контроллера, вы должны имитировать сервисный уровень (то, что вы делаете). В этом виде теста вы просто контролируете это:

  • запускаются правильные методы контроллера, и они производят то, что ожидается
  • правильные методы на сервисном уровне называются... в макете

Вам просто нужно настроить возвращаемые значения методов макета (если это необходимо) или контролировать то, что было вызвано

@Before
public void setup() {
    MockitoAnnotations.initMocks(this);
    this.setMockMvc(MockMvcBuilders.standaloneSetup(paymentController).build());
    // set return values from the mocked service
    when(testService.find(1)).thenReturn(...);
}

и проверить позже, что было вызвано

@Test
public void test() throws Exception {
    this.mockMvc.perform(post("/tr/test").content(...)).andExpect(status().isOk());
    // testService.save(); <-- another way
    verify(testService, times(1)).save();
}

Если вы хотите провести интеграционный тест, вы не имитируете службу, а настраиваете контекст приложения для внедрения реальных bean-компонентов, но обычно используете встроенную базу данных вместо реальной.

person Serge Ballesta    schedule 22.10.2014
comment
Я понимаю, я настраиваю возвращаемое значение. Но я не понимаю основной цели, когда я должен использовать mock. Если я настрою возвращаемое значение, когда это принесет пользу? - person grep; 23.10.2014
comment
Так работает модульное тестирование: вы тестируете только один класс, используя макеты для всех других объектов, с которыми он взаимодействует. Макеты — это тупые объекты, для которых вы настраиваете вывод при вводе данных. Таким образом, вы не сможете провалить тест в классе из-за проблемы в другом классе. - person Serge Ballesta; 24.10.2014

просто измените @InjectMocks на @Autowired. Это исправит проблему! В этом случае вы не издеваетесь, вы вызываете метод с реальными данными.

person grep    schedule 24.11.2014

Насколько я понимаю, вы выполняете публикацию на ресурс "/tr/test", но сопоставление запросов в вашем контроллере - "/payment". Убедитесь, что вы отправляете сообщения в ресурс, отображаемый в контроллере.

person avarabyeu    schedule 22.10.2014