Servant Quickcheck - как узнать, какой маршрут вызвал сбой теста?

Я создаю API с помощью Servant, и, похоже, он работает очень хорошо. И в соответствии с лучшими практиками я пишу для него несколько тестов, следуя официальному руководству здесь. Но я борюсь с этой частью, используя Servant-Quickcheck.

Я пытаюсь использовать его, чтобы проверить, что мой API не выдает 500 ошибок, например:

quickCheckSpec :: Spec
quickCheckSpec = describe "QuickCheck global tests for public API -" $ do
  it "API never gives 500 error" $
    withServantServer publicAPI (return server) $ \burl ->
      serverSatisfies publicAPI burl args (not500 <%> mempty)

но, к сожалению, тест не проходит. Для меня это сюрприз, учитывая, что я не сталкивался с такой ошибкой при тестировании вручную - но, эй, вот почему у нас есть автоматизированные тесты, верно? Особенно с такими инструментами, как QuickCheck, который, насколько я понимаю, должен сосредоточить внимание на «крайних случаях», которые вы, возможно, не подумаете тестировать вручную. (На самом деле я впервые использую QuickCheck в любой форме.)

Проблема, однако, в том, что неудачный тест бесполезен, если вы не знаете, на чем он не удался. И это то, о чем Servant-QuickCheck, похоже, не хочет мне говорить. Единственный вывод, который я получаю относительно провала теста, таков:

  API never gives 500 error FAILED [1]

Failures:

  src\\Servant\\QuickCheck\\Internal\\QuickCheck.hs:146:11: 
  1) QuickCheck global tests for public API - API never gives 500 error
       Nothing

  To rerun use: --match "/QuickCheck global tests for public API -/API never gives 500 error/"

Randomized with seed 1712537046

Finished in 10.8513 seconds
4 examples, 1 failure

(Есть несколько выполненных ранее модульных тестов, которые все проходят - 10 секунд - это еще не все!)

Это довольно сбивает с толку, потому что, как вы можете видеть, нет ничего, что указывало бы на то, как произошел сбой. Поскольку он тестирует API и, насколько я понимаю, выбирает для тестирования допустимые маршруты случайным образом, он должен сообщить мне, на каком маршруте возникла ошибка 500. Но, как видите, там точно ничего нет.

(Я разрабатываю проект с помощью Stack, кстати, и чуть ниже выше написано Logs printed to console, поэтому я не верю, что мне не хватает каких-либо файлов журнала, закопанных где-то, которые могли бы меня просветить. Я не смог найти в моей папке .stack-work.)

Я даже изменил свой args так, чтобы в нем поле chatty было установлено на True, но я все еще получаю только указанное выше.

Единственная подсказка, которую я получаю, которая не связана с QuickCheck, заключается в том, что мой API использует Persistent и регистрирует запросы к базе данных на терминале, поэтому я могу видеть запущенные запросы, которые я, в свою очередь, могу связать с маршрутом. . Однако я не особо доверяю этому, потому что маршрут, выполняющий показанный запрос, определенно работает в ручных тестах. (И это не всегда один и тот же запрос, когда он терпит неудачу.) Есть также несколько простых маршрутов, которые не запрашивают базу данных, поэтому сбой не обязательно связан с последним напечатанным запросом к базе данных (хотя, разумеется, я Я проверил и эти маршруты вручную, и они в порядке).

Я даже задавался вопросом, не может ли проблема быть в том, что QuickCheck поражает мой локальный сервер столько раз подряд, что он просто не может справиться и выдает ошибки, но в этом случае я ожидал бы, что это будет распространенная проблема, отмеченная на в учебнике. (И вывод журнала базы данных предполагает, что на самом деле он всегда дает сбой при самом первом "попадании".)

В любом случае, это всего лишь предположение, и я понимаю, что мне нужно выяснить, почему мой API может не пройти тесты, учитывая, что я не считал нужным делиться какими-либо подробностями о моем реальном API.

На самом деле я спрашиваю: почему мне не говорят, какие маршруты были протестированы, а какие прошли / не прошли, чтобы я, по крайней мере, точно знал, какие маршруты следует исследовать? И есть ли способ заставить Servant-Quickcheck показать мне эту информацию?

Мы будем очень благодарны за любой ответ на этот вопрос.

ДОПОЛНИТЕЛЬНАЯ ИНФОРМАЦИЯ: я пробовал использовать предложение @ MarkusBarthlen ниже, но оно не дало мне дополнительной информации. Тем не менее, он указал на то, что Nothing, который вы видите в моем выводе на консоль, вероятно, каким-то образом является ключевым для этого, потому что в примере Маркуса он получает значение Just, содержащее информацию о запросе. Взглянув на строку 146 , исходный файл, указанный в сообщении об ошибке, явно x там, очевидно, является значением Maybe. Но я не могу понять, что это за тип на самом деле и какое значение имеет то, что он Nothing в моем случае. К сожалению, код выходит за рамки моего собственного опыта / способностей в Haskell - я вижу, что x считывается из MVar, который каким-то образом заполняется результатом теста, но, как я уже сказал, я не могу разобраться в деталях. Но мне действительно нужно знать не только то, почему мой тест не проходит, но и почему это конкретное значение x равно Nothing для меня и что это означает с точки зрения теста. Я был бы очень признателен за ответ, который объясняет это так, как я могу понять.


person Robin Zigmond    schedule 21.11.2019    source источник


Ответы (1)


Из того, что я вижу, вы можете написать RequestPredicate как в https://github.com/haskell-servant/servant-quickcheck/blob/master/src/Servant/QuickCheck/Internal/Predicates.hs, например notLongerThan.

Я тестировал это с

not200b :: RequestPredicate
not200b = RequestPredicate $ \req mgr -> do
     resp <- httpLbs req mgr
     when (responseStatus resp == status200) $ throw $ PredicateFailure "not200b" (Just req) resp
     return []

давая ответ

Неудачи:

src / Servant / QuickCheck / Internal / QuickCheck.hs: 146: 11: 1) Глобальные тесты QuickCheck для общедоступного API - API никогда не дает 200 Failed: Just Predicate failed Predicate: not200b Запрос: Метод: «GET» Путь: / users Заголовки: Тело: Ответ: Код состояния: 200 Заголовки: "Transfer-Encoding": "chunked" "Date": "Fri, 22 Nov 2019 21:32:07 GMT" "Server": "Warp / 3.2.28" "Content- Введите ":" application / json; charset = utf-8 "Body: [{" userId ": 1," userFirstName ":" Isaac "," userLastName ":" Newton "}, {" userId ": 2," userFirstName " ":" Альберт "," userLastName ":" Эйнштейн "}]

Для повторного запуска используйте: --match "/ QuickCheck глобальные тесты для общедоступного API - / API никогда не дает 200 /"

Рандомизировано с семенами 1026627332

Завершено за 0,0226 секунд 1 пример, 1 сбой

person Markus Barthlen    schedule 22.11.2019
comment
Спасибо, я попробую, когда у меня будет шанс - person Robin Zigmond; 23.11.2019
comment
Я пробовал использовать этот подход, но до сих пор не понимаю, что вам нужно. То, что печатается в вашем примере, находится в Just, тогда как я получаю Nothing. (И даже с обычным предикатом - см. Результат в моем вопросе.) Насколько я могу понять из строки 146 github.com/haskell-servant/servant-quickcheck/blob/master/src/, x проводился в MVar должен быть типа Maybe, а в моем случае по какой-то причине это Nothing. Я совершенно не уверен, что это значит. - person Robin Zigmond; 24.11.2019
comment
Даже если бы это была ошибка, было бы неплохо иметь некоторый журнал в вашем приложении. О чем-то говорит тот факт, что он не работает в 4-м примере? - person Markus Barthlen; 27.11.2019
comment
Не совсем, перед ним есть 3 модульных теста (определенно собираюсь добавить больше, но в последнее время я был занят в другом месте и также хочу, чтобы эта проблема с быстрой проверкой была решена), поэтому я думаю, что это просто сводка о том, что он проходит их, но не проходит тест quickcheck. Согласитесь с ведением журнала, я займусь этим, когда у меня будет время (все еще относительно новичок в производственном уровне Haskell, поэтому мне нужно будет посмотреть, как ведется регистрация). - person Robin Zigmond; 27.11.2019