Читатель прочитал мой«Поймите эти восемь основных преимуществ, чтобы овладеть юнит-тестированием»назад,спросите меня:Знать Модульное У новостей есть свои преимущества, но у меня действительно нет времени писать. Прочитав статью, хочу реализовать ее еще раз. Есть что написать? тестированиенавыки?
Этот читатель определенно не первый, кто жалуется мне на модульные тесты. Это легко понять: в Китае слишком много интернет-компаний, которые хотят захватить рынок, и часть этого давления приходится на программистов, которые отчаянно пытаются догнать спрос. Естественно, никто не занимается таким неблагодарным занятием, как модульное тестирование.
Судя по моему многолетнему опыту, написание модульных тестов не задержит проект, а ускорит ход функциональной разработки. Я не буду здесь вдаваться в подробности о преимуществах модульного тестирования. Это смогут понять только те, кто действительно попробовал.
Марк Твен однажды сказал: «Секрет успеха – начать». В этой статье мы хотим поделиться с вами навыками написания хороших модульных тестов и надеемся открыть вам новое направление.
Модульные тесты предназначены для того, чтобы мы могли быстро находить и изолировать неработающие фрагменты кода. По этой причине при тестировании эти функции и классы не должны полагаться на другие элементы, кроме макетов и заглушек. Если при тестировании логика, которую вы пытаетесь охватить, слишком сложна, будет сложно обеспечить надежность покрытия и точно определить причину сбоя.
Поэтому следует отметить, что модульное тестирование включает в себя следующие моменты.
Короткие функции легче читать и понимать. Мы тестируем только одну логическую точку за раз,Поэтому тестовый код должен быть ограничен несколькими строками. Но если это расширенная логика, у нее может быть несколько зависимостей.,Для инициализации макетов и заглушек требуется много шаблонного кода. также,Модульное тестирование То же самое относитсяПринцип DRY (Не повторяйтесь один и только один раз),Когда мы пишем Модульное тестирование, нам следует избегать вставки запутанного кода повсюду копировать,Вместо наследования лучше использовать композицию.
Эйнштейн однажды сказал: «Когда ты чувствуешь, что застрял в жизни,Возможно, вы слишком усложняете ситуацию. "так,когда мы Модульное Когда обучение запутано, возможно, это потому, что мы находимся в Модульном тестирование Используйте сложную логику в。Примечание: цель модульного тестирования — протестировать код, не позволяйте модульному тесту стать частью теста.
Модульные тесты должны использовать длинные и исчерпывающие имена. Такое название может не только четко выражать информацию, но и служить указателем для быстрого поиска соответствующего теста. Даже если требования изменятся, нам нужно внести изменения только для соответствующих тестов, без необходимости смотреть все и проверять, что затронуто.
Хорошее модульное тестирование обычно содержит только одно утверждение.,Так что назвать тоже легко. Например, при обработке расчетов сумм,it('should return 0 for an empty cart')
Чемit('works for 0')
или it('empty cart')
Гораздо лучше。Это также верно для фреймворков, которые используют имена функций в качестве имен тестов.,shouldReturnZeroForAnEmptyCart
Это очень хорошее имя。
Как сказал Дин Лин: «Жизнь подобна восхождению на холм, вы должны делать это шаг за шагом». То же самое справедливо и для модульного тестирования. Не тестируйте весь метод сразу, а делайте это шаг за шагом. Когда мы пишем модульные тесты только для одного требования, код становится легче читать и поддерживать.
Платформа тестирования должна предоставлять различные методы утверждения. Они предоставляют различные способы проверки результатов, а также отображают более конкретные сообщения об ошибках в случае сбоя утверждения, предоставляя больше контекста, чтобы увидеть, что пошло не так.
Например,
expect(result === expected).toBeTruthy();
потерпит неудачу
expect(received).toBeTruthy()
Received: false
хотя
expect(result).toBe(expected);
Будет предоставлена дополнительная информация о конкретных причинах сбоя:
expect(received).toBe(expected) // Object.is equality
Expected: "John Doe"
Received: "JohnDoe"
Платформа также предоставляет различные утверждения для разных стилей тестирования. Например,в использованииJestПри тестировании,toBe
использоватьObject.is
Проверка на точное равенство,иtoEqual
иtoStrictEqual
затем сравните объекты по глубине,Убедитесь, что они одинаковы по типу и структуре.
Чтобы определить, равны ли числа с плавающей запятой,Нам нужно использовать специальный сопоставитель,Этот сопоставитель способен игнорировать небольшие ошибки округления, вызванные тем, как числа с плавающей запятой представлены в памяти. В шутку,СопоставительtoBeCloseTo
。ХотяtoEqual
Иногда это работает,Но даже такой, казалось бы, простой тест,нравитьсяexpect(0.1+0.2).toEqual(0.3)
Может не пройти。
Следуя принципам AAA (Arrange, Act, Assert, Arrangement, Execution, Assert), вы можете умело улучшить ясность, надежность и удобство сопровождения кода модульного теста.
Первый шаг — этап аранжировки. Нам необходимо выполнить назначение переменных, создание экземпляра объекта и остальную предварительную настройку, необходимую для запуска теста, а также определить ожидаемые результаты. Преимущество этого в том, что, с одной стороны, нам нужно иметь четкие ожидания перед выполнением логики тестирования, с другой стороны, удобнее просматривать ожидаемый результат сразу после ввода данных, что помогает избежать путаницы в коде.
Второй шаг – это этап исполнения (Акт). Мы выполним тестовую функцию и сохраним ее результаты. Хранение результатов на самом деле является естественным продолжением подготовительной работы и помогает нам просматривать и обобщать результаты.
Третий шаг — этап утверждения (Assert). На этом этапе мы можем судить о правильности гипотезы. Это основа модульного тестирования, поскольку эта ссылка на самом деле является проверкой определенного конкретного контента. Цель состоит в том, чтобы проверить, соответствуют ли фактические результаты ожидаемым.
Нам необходимо обеспечить надежность кода,Избегайте неправильного ввода, отсутствующих параметров, пустых данных, исключений при вызове функций и т. д. Инструменты покрытия кода могут помочь нам найти и заполнить пробелы.,Найдите непроверенные ветки кода。Мы всегда должны четко понимать цели наших модульных тестов. Чрезмерное стремление к 100%-ному покрытию тестами сделает код модульного теста все более и более сложным. Это совпадает с аргументом в «Весенних и осенних анналах Лу»: «Если вы не знаете важности, то тяжелые будут считаться легкими, а легкие будут тяжелыми. Если это так, то каждое движение будет непобедим».
Чтобы сделать модульное тестирование более эффективным, нам нужно имитировать все внешние зависимости, которые могут повлиять на скорость, такие как вызовы API, доступ к базе данных или файловой системе. Когда мы пишем модульные тесты, мы должны стараться избегать сна, ожидания и тайм-аутов потоков. Если необходимо установить тайм-аут, его следует сократить до нескольких миллисекунд. При работе с многопоточностью или асинхронной гонкой точный контроль состояния триггера гораздо более эффективен, чем простое ожидание.
Модульные тесты должны гарантировать, что ничего не изменится за пределами области действия. Если тест завершается успешно только при выполнении в определенном порядке, это может указывать на проблему с тестовым набором или тестовым кодом. Каждый тестовый пример должен работать независимо. Поскольку современные среды тестирования по умолчанию выполняют тесты параллельно, нам не следует полагаться на глобальные переменные или эффекты наследия предыдущих тестов. Это одна из причин, почему глобальные переменные часто считаются плохой практикой программирования, поскольку они могут скрыть истинные зависимости, привести к большей связности кода и требуют особой осторожности при решении проблем многопоточности.
Если тестирование требует сложной повторяющейся настройки, вам следует воспользоваться возможностями настройки и очистки, предоставляемыми платформой. Эти функции гарантируют, что соответствующий код может быть выполнен до и после запуска каждого тестового примера или всего набора тестов. Таким образом, независимо от того, запускаете ли вы тесты по отдельности или как часть набора тестов, результаты ваших тестов будут детерминированными, и порядок выполнения не повлияет на результаты тестов.
«Сюньцзы-Далуэ»: «Если ты извлекаешь максимум пользы из малого, ты станешь великим; если ты накапливаешь малое, ты станешь великим произведением; если ты добродетелен, твой внешний вид будет гармоничен; если ты приложишь все усилия , ваша репутация будет иметь далеко идущие последствия». Роль модульного тестирования станет значимой только после длительного накопления. На самом деле написание модульных тестов — это скорее ответственность за собственный код. Код с тестовыми примерами легче понять другим. Когда другие возьмут на себя ваш код в будущем, они могут свободно вносить изменения.
По вышеописанному методу юнит-тестирование не представляет сложности. Ведь «нет ничего сложного в мире, только тот, кто захочет». Я обнаружил, что многие читатели интересуются модульным тестированием, и кто-то спросил меня, следует ли проводить модульное тестирование путем тестирования или разработки. Если вам интересно, я также могу написать статью и кратко поделиться ею с вами.
*Текст ссылки: Андрей Обризан, Как писать хорошие модульные тесты: 14 советов