Веб-поддержка 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
. Вы также сможете указать, какой экземпляр вы хотите использовать, не извлекая его из базы данных. Чтобы узнать больше о том, как имитировать этот сервис, посмотрите этот ответ.