Веб-поддержка Mockito Spring Data

Я новичок в Mockito, и у меня возникли проблемы с веб-поддержкой Spring Data.

У меня есть следующая функция в моем контроллере.

@DeleteMapping("/")
public MyObject delete(@RequestParam("id")MyObject object){
...do something
}

что здесь происходит (в реальных случаях) здесь описано.

Проблема в том, что когда я использую MockMvc и Mockito в моем unitTests, нет базы данных и репозитариев постоянства. Как я могу заставить Spring использовать mockRepository для замены идентификатора, переданного в /?id=1 экземпляром MyObject по моему выбору.

Вот как выглядит тест:

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;

import com.mine.OrgUnitController;
import com.mine.OrgUnitService;

@RunWith(SpringJUnit4ClassRunner.class)
public class OrgUnitControllerTest2 {
    private MockMvc mockMvc;
    @Mock
    SomeService someService;
    @InjectMocks
    MyController controller;

    @Before
    public void init() {
        MockitoAnnotations.initMocks(this);
        mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
    }

    @Test
    public void test_delete() throws Exception {
        mockMvc.perform(delete("/?id=1")).andExpect(status().isOk());
    }
}

Я действительно ценю любую помощь.

4 ответа

Решение

Ну, решение очень простое, и оно обошлось мне всего в 2 дня.;) Чтобы заставить SpringDataWebSupport работать, Spring использует org.springframework.data.repository.support.DomainClassConverter который является ConversionService. Следующее, что нужно знать, это то, что MockMvc принимает ConversionService через setConversionService(), поэтому осталось только написать свой собственный ConversionService, который на самом деле очень прост. Я продлил DefaultFormattingConversionService как это:

public class MockSpringDataWebSupport extends DefaultFormattingConversionService {
    /**
     * @param converters {@link Converter Converters} that shall be added to this {@link ConversionService}
     */
    @SafeVarargs
    public MockSpringDataWebSupport(Converter<? extends Object, ? extends Object>... converters) {
        for (Converter<? extends Object, ? extends Object> converter : converters) {
            this.addConverter(converter);
        }
    }
}

таким образом, я мог бы передать любой конвертер Кустома, который соответствует моим потребностям для тестирования. В этом особом случае я использовал:

        mockMvc = MockMvcBuilders.standaloneSetup(controller)
            .setConversionService(new MockSpringDataWebSupport(new Converter<String, MyObject>() {
                @Override
                public OrgUnit convert(String source) {
                    return new MyObject();
                }
            })).build();

И это сработало.

Вам, вероятно, нужно установить setCustomArgumentResolvers в MockMvc объект, как это:

@Before
  public void init() {
      MockitoAnnotations.initMocks(this);
      mockMvc = MockMvcBuilders
          .standaloneSetup(controller)
          .setCustomArgumentResolvers(new HandlerMethodArgumentResolver(){...})
          .build();
   }

Вы должны выяснить, какой класс реализует HandlerMethodArgumentResolver а затем использовать это в init() метод выше.

Вы можете взглянуть на этот ресурс.

Я думаю, вам будет проще, если вы просто используете Mockito вместо Mockito + MockMvc,

Вы могли бы сделать что-то вроде этого:

@RunWith(SpringJUnit4ClassRunner.class)
public class OrgUnitControllerTest2 {
    @Mock
    SomeService someService;
    @InjectMocks
    MyController controller;

    @Before
    public void init() {
        MockitoAnnotations.initMocks(this);
    }

    @Test
    public void test_delete() throws Exception {
        //given
        given(someService.delete(1)).willReturn(true); //or successful response

        //when
        MyObject response = controller.delete(1);

        //then
        assertTrue(OK, response.getStatus())
    }
}

Чтобы вернуть MyObject для данного идентификатора, вы можете использовать when(…​.).thenReturn(…​.), Поэтому, когда у вас есть метод в SomeService для поиска MyObject по идентификатору, вы можете заглушки и вернуть значения.

// When the get method is called, it will return MyObject
when(someService.get(id)).thenReturn(new MyObject());

Как я могу заставить Spring использовать mockRepository для замены идентификатора, переданного в /? Id=1, экземпляром MyObject по моему выбору

Вы можете сделать это, высмеивая WebConversionService, что позволит избежать поиска в базе данных через репозиторий сущностей findById. Вы также сможете указать, какой экземпляр вы хотите использовать, не извлекая его из базы данных. Чтобы узнать больше о том, как имитировать этот сервис, посмотрите этот ответ.

Другие вопросы по тегам