Тестирование конечной точки REST с помощью Spring, MongoDB с использованием ObjectIds - PullRequest
1 голос
/ 27 марта 2019

Я новичок в MongoDB и пишу серию модульных тестов для веб-службы REST, поддерживаемой Mongo.Вот простой тест для точки / client / {id}:

@RunWith(MockitoJUnitRunner.class)
public class ClientsControllerMockMvcStandaloneTest {

    private MockMvc mvc;

    @Mock
    private ClientsRepository clientsRepository;

    @Mock
    private ModelMapper modelMapper;

    @InjectMocks
    private ClientsController clientsController;

    private ExceptionHandlerExceptionResolver createExceptionResolver() {

        ExceptionHandlerExceptionResolver exceptionResolver = new ExceptionHandlerExceptionResolver() {

            @SuppressWarnings("ConstantConditions")
            @Override
            protected ServletInvocableHandlerMethod getExceptionHandlerMethod(final HandlerMethod handlerMethod,
                                                                              final Exception exception) {

                final Method method = new ExceptionHandlerMethodResolver(RestResponseEntityExceptionHandler.class)
                        .resolveMethod(exception);

                final RestResponseEntityExceptionHandler handler = new RestResponseEntityExceptionHandler();

                return new ServletInvocableHandlerMethod(handler, method);
            }
        };

        exceptionResolver.getMessageConverters().add(new MappingJackson2HttpMessageConverter());
        exceptionResolver.afterPropertiesSet();

        return exceptionResolver;
    }

    @Before
    public void setup() {

        JacksonTester.initFields(this, new ObjectMapper());

        mvc = MockMvcBuilders.standaloneSetup(clientsController)
                .setHandlerExceptionResolvers(createExceptionResolver())
                .build();
    }

    // GET /api/clients/{id} 200

    @Test
    public void findById_ClientEntryFound_ShouldReturnFoundClientEntry() throws Exception {

        final ObjectId id = new ObjectId();

        final Client client = Client.builder()
                .id(id)
                .name("Microsoft")
                .build();

        final ClientDTO clientDTO = ClientDTO.builder()
                .id(id)
                .name("Microsoft")
                .build();

        when(clientsRepository.findById(id))
                .thenReturn(Optional.of(client));

        when(modelMapper.map(client, ClientDTO.class))
                .thenReturn(clientDTO);

        mvc.perform(get("/clients/" + id.toString())
                .accept(TestUtils.APPLICATION_JSON_UTF8))
                .andExpect(content().contentType(TestUtils.APPLICATION_JSON_UTF8))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.id", is(id)))
                .andExpect(jsonPath("$.name", is("Microsoft")))
                .andDo(MockMvcResultHandlers.print());

        verify(modelMapper, times(1)).map(client, ClientDTO.class);
        verify(clientsRepository, times(1)).findById(id);

        verifyNoMoreInteractions(clientsRepository);
    }
}

Я ожидаю, что это сработает, но я получаю следующее:

java.lang.AssertionError: JSON path "$.id"
Expected: is <5c9b9a0289d2b311b150b92c>
     but: was <{timestamp=1553701378, machineIdentifier=9032371, processIdentifier=4529, counter=5290284, timeSecond=1553701378, time=1553701378000, date=1553701378000}>
Expected :is <5c9b9a0289d2b311b150b92c>
Actual   :<{timestamp=1553701378, machineIdentifier=9032371, processIdentifier=4529, counter=5290284, timeSecond=1553701378, time=1553701378000, date=1553701378000}>
 <Click to see difference>

Любая помощь будет принята с благодарностью(включая любые указатели, если вы думаете, что мой общий подход может быть улучшен!).

Приветствия!

1 Ответ

2 голосов
/ 27 марта 2019

Джексон не знает, что ваш экземпляр ObjectId должен быть сериализован как 5c9b9a0289d2b311b150b92c, а не как:

{
  "timestamp": 1553701378,
  "machineIdentifier": 9032371,
  "processIdentifier": 4529,
  "counter": 5290284,
  "time": 1553701378000,
  "date": 1553701378000,
  "timeSecond": 1553701378
}

К счастью, это легко исправить.Метод ObjectId#toString() (который будет внутренне вызывать ObjectId#toHexString()) позволяет преобразовать экземпляр ObjectId в 24-байтовое шестнадцатеричное строковое представление.

Таким образом, вы можете использовать @JsonSerialize вместе с ToStringSerializer, чтобы экземпляр ObjectId был представлен в виде строки:

@JsonSerialize(using = ToStringSerializer.class)
private ObjectId id;

Затем в своем тесте используйте метод ObjectId#toString() (или ObjectId#toHexString()) для утверждения:

.andExpect(jsonPath("$.id", is(id.toString())))

В качестве альтернативы, если вы используете Spring Data для MongoDB, вместо ObjectId вы можете использовать:

@Id
private String id;

Вы также можете обработать преобразование ObjectId до String в вашем слое картографирования.

...