Я тестирую REST API. Допустим, он возвращает структуру JSON. Каков наилучший подход к тестированию сервера? Каждый шаг теста может быть успешным, только если все предыдущие были успешными.
Структура A: проверить все сразу
- Test method 1:
- make server request
- assert http response code was 200
- assert returned file is not empty
- assert returned file has valid JSON syntax
- assert returned JSON contains key X
Это, кажется, лучшее решение.
Преимущества:
- Только один запрос к серверу
- Я тестирую поведение в целом "Возвращает ли сервер JSON с ключом X?"
Структура B: постепенно добавляйте утверждения к каждому тесту
- Test method 1:
- make server request
- assert http response code was 200
- Test method 2:
- make server request
- assert returned file is not empty
- Test method 3:
- make server request
- assert returned file has valid JSON syntax
- Test method 4:
- make server request
- assert returned JSON contains key X
Именно так я начал делать это, и я был убежден, что так и должно быть, потому что каждый метод тестирует только одну вещь, и это создает лучшее разделение. Но теперь я думаю, что, поскольку это не модульные тесты, мое разделение не подходит, и я должен проверить поведение в целом.
Структура C: сделать запрос один раз и запустить отдельные методы тестирования для кэшированного ответа
- make server request and cache it (allow read-only access)
- Test method 1:
- assert http response code was 200 on cached server request
- Test method 2:
- assert returned file is not empty on cached server request
- Test method 3:
- assert returned file has valid JSON syntax on cached server request
- Test method 4:
- assert returned JSON contains key X on cached server request
Преимущества:
- Нет повторного (дорогого) запроса к серверу
- По-прежнему имеет методы проверки одного утверждения
Какую тестовую структуру наиболее целесообразно использовать?
testing
acceptance-testing
mrplow
источник
источник
Ответы:
У лучших практик всегда есть цель, причина за ними. Это всегда хорошая идея, чтобы учесть эти причины в своем дизайне, особенно когда вы пытаетесь решить, как и насколько сложно следовать этим лучшим практикам.
В этом случае главная причина создания каждого тестового теста - одна вещь, если первая не удалась, вторая не будет проверена. Поскольку слишком много лиц, формирующих общественное мнение, похоже, находят смысл разбивать все на мелкие биты и оборачивать каждый бит как можно большим количеством раздувания, это породило идею о том, что каждый тест должен содержать одно утверждение.
Не следуй этому вслепую. Даже если каждый тест должен проверять одну вещь, вы все равно должны подумать о том, какой большой или маленькой должна быть каждая «вещь», и для этого вы должны помнить, почему вы хотите, чтобы каждый тест проверял одну вещь - чтобы убедиться, ошибка в первой вещи не оставляет вторую вещь непроверенной.
Итак, вы должны спросить себя: «Мне действительно нужна эта гарантия здесь?»
Допустим, в первом тесте есть ошибка - код ответа HTTP - нет
200
. Итак, вы начинаете взламывать код, выяснять, почему вы не получили код ответа, который вы должны иметь, и устранять проблему. И что теперь?Есть еще несколько вещей, чтобы рассмотреть:
Утверждения зависимостей
Я знаю, что тесты, которые вы описали, являются лишь примером, и ваши реальные тесты, вероятно, являются более сложными - поэтому то, что я собираюсь сказать, может оказаться недействительным с такой большой силой в реальных тестах, но все же может быть несколько эффективным, так что вы может захотеть рассмотреть это.
Если у вас есть служба REST (или любой другой протокол HTTP), который возвращает ответы в формате JSON, вы обычно пишете простой клиентский класс, который позволяет вам использовать методы REST, такие как обычные методы, которые возвращают обычные объекты. Если предположить, что у клиента есть отдельные тесты, чтобы убедиться, что он работает, я бы отбросил первые 3 утверждения и оставил только 4!
Почему?
Таким образом, вам не нужно запускать все эти тесты - просто запустите четвертый тест, и, если обнаружатся какие-либо ошибки, обнаруженные первыми тремя попытками, тест завершится неудачно с правильным исключением, прежде чем вы даже получите фактическое утверждение.
Как вы хотите получать отчеты?
Допустим, вы не получаете электронные письма с тестового сервера, но вместо этого отдел QA проводит тесты и уведомляет вас о неудачных тестах.
Джек из QA стучит в вашу дверь. Он говорит, что первый метод тестирования не удался, а метод REST вернул неверный код ответа. Вы благодарите его и начинаете искать основную причину.
Затем приходит Джен из QA и говорит, что третий метод тестирования не удался - метод REST не вернул допустимый JSON в теле ответа. Вы говорите ей, что вы уже просматриваете этот метод, и вы полагаете, что то же самое, что заставило его вернуть неверный код выхода, также заставило его вернуть что-то, что не является допустимым JSON и больше похоже на трассировку стека исключений.
Вы возвращаетесь к работе, но затем приходит Джим из QA, говоря, что четвертый метод теста не удался, и в ответе нет ключа X ...
Вы даже не можете найти причину, потому что трудно смотреть на код, когда у вас нет экрана компьютера. Если бы Джим был достаточно быстр, он мог бы вовремя уклониться ...
Электронные письма с тестового сервера легче отклонить, но все же - не лучше ли вам просто ОДНАЖДЫ раз сообщать , что что-то не так с методом теста, и самостоятельно просматривать соответствующие журналы тестов?
источник
Если вы можете с уверенностью предположить, что выполнение запроса к серверу с одинаковыми параметрами будет вести себя всегда одинаково, метод B практически бессмысленен - зачем вам четыре раза вызывать один и тот же метод для получения одних и тех же данных ответа четыре раза, когда достаточно одного вызова?
И если вы не можете с уверенностью предположить это и захотите включить его в тест, вам лучше будет выполнить тест А несколько раз.
Единственная гипотетическая ситуация, которую я вижу, где B может принести выгоду, - это когда ваша структура тестирования позволяет включать и выключать только явные методы тестирования, и вы ожидаете необходимость сделать это для отдельных этапов вашего теста.
Альтернатива C, кажется, объединяет A с одним преимуществом, которое я упомянул выше для B. Если ваша инфраструктура тестирования позволяет легко и просто структурировать ваш код без больших накладных расходов над B, это выполнимый подход. Тем не менее, это добавляет некоторую дополнительную сложность к A, поэтому я бы использовал его, только если я когда-нибудь захочу включить и выключить отдельные тесты, в противном случае примените принцип YAGNI и придерживайтесь самого простого решения (A).
TLDR: начните с A, если вы уверены, что всегда хотите, чтобы все утверждения выполнялись в одном тесте, измените рефакторинг на C, если вы заметили, что вам нужно иметь более легкий контроль со стороны для отдельных утверждений.
источник
Как и любой код, избегайте преждевременной оптимизации. Сначала напишите свои тесты, чтобы их было легко читать и поддерживать. Когда тесты станут слишком медленными, оптимизируйте их. В вашем довольно простом примере и A, и B будут легко читаться и обслуживаться, поэтому выбирайте тот, который вам нужен, пока все не станет слишком медленным (структура B) или слишком сложным (структура A).
Если ваш сервер не имеет состояния, вы можете оптимизировать его, сравнивая фактический ответ с ожидаемым, чтобы проверить все сообщение за один раз. Очевидно, что это будет за счет читабельности.
Если ваш сервер заполнен, и вам нужно сделать несколько медленных вызовов API, чтобы привести сервер в состояние для теста, тогда вы должны использовать другой подход, иначе тесты могут занять несколько минут. Например, вы можете запустить обновление базы данных, чтобы внедрить данные в тестовую базу данных, чтобы вы могли быстро получить объект в подходящем состоянии для тестирования. Тест быстрый и читаемый, но сложнее в обслуживании. В качестве альтернативы вы можете написать фасад перед API, чтобы несколько вызовов API стали едиными вызовами API, которые более точно соответствуют бизнес-процессу, который вы тестируете.
источник
Тесты не должны делиться вещами - начиная с нуля, вы избегаете влияния одного теста на другой. Это также позволяет запускать тесты в произвольном порядке.
Таким образом, путь C не должен быть принят.
При написании любого кода (или, возможно, даже при создании чего-либо еще), всегда спрашивайте себя: «Почему существует такая практика?»
Почему мы говорим, что должны быть разные тесты для всего?
Есть два случая, когда это нужно:
Есть две причины, по которым вы сталкиваетесь с этими случаями:
Если вы по какой - то причине не может объявить по крайней мере , одной из этих причин , чтобы иметь место только слепо взять структуру B .
В противном случае (я надеюсь , что вы здесь) вы выбираете A .
Также вы можете задать этот вопрос на сайте Stackexchange по обеспечению качества и тестированию программного обеспечения .
источник