Ошибка в совпадении java .util.Date при использовании Hamcrest в модульном тесте - PullRequest
0 голосов
/ 12 апреля 2020

Я пишу контрольный пример для контроллера REST. Код ниже:

 private SimpleDateFormat dateFormat = new SimpleDateFormat("dd/MM/yy");
     @Test
     public void getByExternalTransactionId() throws Exception {
            EquityFeeds equityFeeds = new EquityFeeds(423,"SAPEXTXN1", "GS", "ICICI", "BUY", dateFormat.parse("22/11/13"), 101.9f, "BLO", "Y",0);
            when(equityFeedsService.findByExternalTransactionId("SAPEXTXN1")).thenReturn(equityFeeds);
            mockMvc.perform(MockMvcRequestBuilders.get("/equityFeeds/getByExternalTransactionId/{externalTransactionId}", "SAPEXTXN1"))
                    .andExpect(status().isOk())
                    .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
                    .andExpect(jsonPath("$.*", Matchers.hasSize(10)))
                    .andExpect(jsonPath("$.id", Matchers.is(423)))
                    .andExpect(jsonPath("$.externalTransactionId", Matchers.is("SAPEXTXN1")))
                    .andExpect(jsonPath("$.clientId", Matchers.is("GS")))
                    .andExpect(jsonPath("$.securityId", Matchers.is("ICICI")))
                    .andExpect(jsonPath("$.transactionType", Matchers.is("BUY")))
    //                .andExpect(jsonPath("$.transactionDate", Matchers.is(dateFormat.parse("22/11/13"))))
                    .andExpect(jsonPath("$.transactionDate", Matchers.is(Date.parse("22/11/13"))))       
                    .andExpect(jsonPath("$.marketValue", Matchers.is(101.9f)))
                    .andExpect(jsonPath("$.sourceSystem", Matchers.is("BLO")))
                    .andExpect(jsonPath("$.priorityFlag", Matchers.is("Y")))
                    .andExpect(jsonPath("$.processingFee", Matchers.is(0)));
            verify(equityFeedsService, times(1)).findByExternalTransactionId("1");
            verifyNoInteractions(equityFeedsService);
        }

Проблема:

Это сбой в транзакции транзакции, которая java.util.Date в POJO. Я попытался ниже в тестовом случае:

.andExpect(jsonPath("$.transactionDate", Matchers.is(dateFormat.parse("22/11/13"))))

Это дает мне вывод

java.lang.AssertionError: JSON path "$.transactionDate"
Expected: is <Fri Nov 22 00:00:00 IST 2013>
     but: was <1385058600000L>
Expected :is <Fri Nov 22 00:00:00 IST 2013>
Actual   :<1385058600000L>

Затем я попытался:

.andExpect(jsonPath("$.transactionDate", Matchers.is(Date.parse("22/11/13"))))

Это дало мне вывод :

java.lang.AssertionError: JSON path "$.transactionDate"
Expected: is <1412965800000L>
     but: was <1385058600000L>
Expected :is <1412965800000L>
Actual   :<1385058600000L>

Это выглядит очень близко. Я понимаю, что разница в значении заключается в том, что время создания даты в POJO составляет миллисекунды и отличается от времени создания даты в строках .andExpect(jsonPath("$.transactionDate", Matchers.is(Date.parse("22/11/13")))), и, следовательно, значения отличаются, так как значения являются длинными, поскольку значения в миллисекундах.

Мой TestCase не работает только из-за этого поля. Я действительно сошел с ума относительно того, как я должен решить это. Я должен использовать java .util.Date. Любое другое решение для этого?

1 Ответ

0 голосов
/ 12 апреля 2020

Редактировать: Если я правильно понимаю (не знаком с Hamcrest), вам нужно вставить старомодный объект java.util.Date в конструктор EquityFeeds и проверить, что значение long, которое вы получите обратно - 1385058600000L или 1 385 058 600 000 - согласен с указанным вами Date.

java .time

Для построения java.util.Date, что вам нужно:

    Instant transactionTime = LocalDate.of(2013, Month.NOVEMBER, 22)
            .atStartOfDay(ZoneId.systemDefault())
            .toInstant();
    Date oldfashionedDate = Date.from(transactionTime);
    System.out.println(oldfashionedDate);

Вывод данных при работе в часовом поясе Азия / Калькутта:

Пт 22 ноября 00:00:00 IST 2013

Теперь просто передайте oldfashionedDate как шестой аргумент конструктора EquityFeeds. Суть в приведенных выше строках кода заключается не только в том, что мы используем java .time, современный Java API даты и времени, и очень ясно из кода, что он делает; это также облегчает тестирование. Чтобы получить ожидаемое значение long:

    long expectedTransactionDateMillis = transactionTime.toEpochMilli();
    System.out.println(expectedTransactionDateMillis);

1385058600000

Не будучи знакомым с Hamcrest и не попробовав, я бы ожидал, что вам просто нужно заполнить это значение в вашем утверждении:

            .andExpect(jsonPath("$.transactionDate", Matchers.is(expectedTransactionDateMillis)))

Класс java.util.Date плохо спроектирован и давно устарел. Я рекомендую не использовать его, и еще более настоятельно рекомендую не использовать общеизвестно хлопотный класс SimpleDateFormat. Несмотря на то, что Date используется в вашем производственном коде по историческим причинам, я не вижу причин, почему вы должны повторить эту ошибку в своих тестах. Используйте java .time, с ним гораздо приятнее работать. И преобразования существуют, когда вам нужен объект одного из устаревших типов, например Date.

Что пошло не так в вашем тесте?

Ваша первая попытка:

            .andExpect(jsonPath("$.transactionDate", Matchers.is(dateFormat.parse("22/11/13"))))

Результат dateFormat.parse("22/11/13") равен java.util.Date. Даже если это равно Date в вашем POJO, значение в вашем JSON - это long, представляющее количество миллисекунд с начала эпохи (эту практику вы можете изменить, если сможете). Поскольку Date и long никогда не могут быть равны, ваш тест не пройден.

Затем вы попытались:

            .andExpect(jsonPath("$.transactionDate", Matchers.is(Date.parse("22/11/13"))))

Теперь вы получаете значение long в порядке. Мы видим, что ожидаемые и фактические значения имеют одинаковый формат в печатном виде. Есть две неправильные вещи:

  1. Вы используете метод Date.parse, который устарел с 1997 года. Так было, потому что он работает ненадежно во всех часовых поясах. Даже если вы настаивали на использовании Date, вы все равно должны держаться подальше от этих устаревших методов и конструкторов.
  2. Ваша строка даты разбирается на 1 412 965 800 000, что равно 2014-10-11T00: 00 +05: 30, так что сейчас почти год. Этот метод не только устарел, но также сбивает с толку и анализирует вашу строку даты как 11-й день 22-го месяца 2013 года. 22-го месяца года нет, но метод parse просто экстраполирует, продолжает подсчитывать месяцы до 2014 и заканчивается в октябре того года. Еще одна причина не использовать этот метод.

Ссылка

Oracle учебник: Дата и время , объясняющие, как использовать java .time.

...