Будучи консультантом по тестированию, я за годы работы прочитал массу статей по QA. Большинство из них — это в какой-то степени полезные, но часто случайные материалы, которые не всегда стоят времени. Но иногда я натыкался на удивительно хорошие, по моему мнению, статьи, которые действительно могут помочь улучшить навыки написания тестов. Я отобрал эти статьи и написал к ним аннотации. Половина из них относится непосредственно к JavaScript/Node.js, вторая половина охватывает общие концепции тестирования, которые применимы в любом языке.
Почему эти статьи показались мне выдающимися? Во-первых, они отлично написаны. Во-вторых, они посвящены «новому миру тестирования» — не общеизвестным «TDD-шным» вещам, а современным концепциям и инструментам.
Если вы слишком заняты, чтобы прочитать их все, то ищите статьи, отмеченные тремя звездочками *** — это шедевры, которые ни в коем случае нельзя пропускать.
1. «Выборочное юнит-тестирование — плюсы и минусы»
Автор: Стив Сандерсон (Steve Sanderson)
9 мин (1850 слов), статья
Аннотация: Все мы хотя бы раз участвовали в оживленной дискуссии о «юнитах» и «интеграции». В этой статье автор выходит на более высокий уровень конкретики и рассуждает о том, КОГДА юнит-тесты хороши, рассмотрев затраты на написание этих тестов в различных сценариях. Многие относятся к своей стратегии тестирования как к статической модели — технике тестирования, к которой они прибегают всегда, независимо от контекста. «Всегда пишите юнит-тесты на функции», «Пишите в основном интеграционные тесты» — такие аргументы часто можно услышать. В данной статье, напротив, предлагается оценивать целесообразности юнит-тестов, исходя из затрат на модуль и выгод. В статье классифицируется несколько сценариев, в которых чистая ценность юнит-тестов высока или низка, например:
Если ваш код в принципе очевиден — то есть с первого взгляда понятно, что именно он делает, — то дополнительное проектирование и верификация приносят крайне минимальную пользу.
Автор также использует модель 2×2 для визуализации того, когда привлекательность юнит -тестов высока или низка:
Примечание, не относящееся к статье: лично я (Йони) всегда начинаю с компонентных тестов, охватывая сначала высокоуровневые детали пути пользователя (так называемый ромб тестирования). Затем, когда появляются функции, я добавляю юнит-тесты, основываясь на их чистой ценности. Эта статья помогла мне классифицировать и оценить преимущества юнит-тестов в различных сценариях.
Ссылка на статью: https://blog.stevensanderson.com/2009/11/04/selective-unit-testing-costs-and-benefits/
2. «Тестирование деталей реализации» (пример на JavaScript)
Автор: Kent C Dodds (Kent C Dodds)
13 мин (2600 слов), статья
Аннотация: Автор на примере кода описывает неизбежную трагичность веры тестировщика, который делает ставку на детали реализации. Если не принимать во внимание усилия, затрачиваемые на тестирование такого количества деталей, то такой путь всегда заканчивается «ложноположительными» и «ложноотрицательными» результатами. Это ставит под сомнение надежность тестов. Статья иллюстрирует этот тезис на примере фронтенд-кода, но выводы из урока универсальны для любого вида тестирования.
«Есть две причины, почему важно избегать тестирования деталей реализации. Тесты, проверяющие детали реализации:
- Могут сломаться при рефакторинге кода приложения. Ложноотрицательные результаты
- Могут не сработать, когда вы ломаете код приложения. Ложноположительные результаты».
Ссылка на статью: https://kentcdodds.com/blog/testing-implementation-details
p.s. У этого автора есть еще одна замечательная статья о современной стратегии тестирования — «Пишите тесты. Не слишком много. В основном интеграционные».
3. «Разумный способ тестирования микросервисов» ***
Автор: Синди Сридхаран
Время чтения: > 2 часов (10 500 слов с большим количеством ссылок), статья
Аннотация: Это целая библия по тестированию микросервисов и современного распределенного тестирования, упакованная в одну длинную увлекательную статью. Помню, когда я наткнулся на нее четыре года назад, я каждый день перед сном проводил час с улыбкой на лице, читая ее. Я внимательно переходил по каждой ссылке, делал паузу после каждого абзаца, чтобы подумать — передо мной открывался совершенно новый мир. Это было настолько увлекательно, что мне захотелось специализироваться в этой области. Спустя годы это стало основной часть моей работы, и я наслаждаюсь каждым моментом.
Эта статья начинается с объяснения, почему E2E и юнит-тесты не оправдывают ожиданий в распределенной среде. А также почему любого вида закодированных тестов будет недостаточно, а необходим богатый набор методик. В статье рассматривается ряд современных методов тестирования, незнакомых большинству разработчиков. Одна из ключевых частей книги посвящена тому, что должно быть канонической техникой тестирования у разработчиков: автор выступает за «большие юнит-тесты» (т.е. компонентные тесты), поскольку они обеспечивают баланс между удобством для разработчиков и реалистичностью.
Я придумал термин «step-up testing», общая идея которого заключается в том, чтобы тестировать на один уровень выше того, что обычно пропагандируется. Согласно этой модели, юнит-тесты будут больше походить на интеграционные (рассматривая ввод/вывод как часть тестируемого модуля в ограниченном контексте), интеграционное тестирование будет больше походить на тестирование в продакшене, а тестирование в продакшене будет больше походить на мониторинг и исследование. Реорганизованная тестовая пирамида (тестовая воронка) для распределенных систем будет выглядеть следующим образом:
Вне зависимости от того, с каким типом системы вы имеете дело, эта статья расширит ваш взгляд на тестирование и подарит множество новых идей.
Ссылка на статью: https://copyconstruct.medium.com/testing-microservices-the-sane-way-9bb31d158c16
4. «Как проводить юнит-тестирование с Node.js?» (примеры на JavaScript, для начинающих)
Автор: Райан Джонс (Ryan Jones)
16 мин (3000 слов), статья
Аннотация: это единственная статья из списка, подходящая новичкам в тестировании.
Это руководство я выбрал из множества других вариантов потому, что оно относительно полное и хорошо написано. В нем рассматриваются шаги, о которых новичку следует узнать в первую очередь: интерфейс программ для запуска тестов, CLI программы Test Runners, проверка утверждений и асинхронные тесты. Разумеется, этих знаний будет недостаточно для того, чтобы покрыть тестами реальное приложение, но они позволят благополучно перейти к следующему этапу. Мой личный совет: после прочтения этой статьи стоит перейти к изучению тестовых дублеров (моков).
Ссылка на статью: https://medium.com/serverlessguru/how-to-unit-test-with-nodejs-76967019ba56
5. «Фетиш юнит-тестов»
Автор: Мартин Сустрик
5 мин (1000 слов), статья
Аннотация: Статья начинается словами: «Я слышал, что в наши дни люди испытывают неконтролируемое желание писать юнит-тесты. Если вы один из них, потратьте несколько минут на изучение причин, по которым писать юнит-тесты НЕЛЬЗЯ». Несмотря на такое неоднозначное вступление, автор статьи не выступает против юнит-тестов как таковых, а скорее подчеркивает, когда и где юнит-тесты оказываются неэффективными. В этих случаях следует рассмотреть другие методы. Вот пример: Юнит-тесты по своей природе имеют более низкий ROI (return on investment, рентабельность вложений), и автор приводит звучную метафору: «Приступая к покраске дома, вы начинаете с самой большой кисти, а маленькую кисть оставляете на конец, чтобы разобраться с мелкими деталями». Начиная свою работу по QA с юнит-тестов, вы, по сути, пытаетесь расписать весь дом самой тонкой китайской кисточкой для каллиграфии…».
Ссылка на статью: https://250bpm.com/blog:40/
6. «Наличие моков — это признак плохого кода» (примеры на JavaScript)
Автор: Эрик Эллиотт
32 мин (6 300 слов), статья
Аннотация: Большинство статей из этого списка относятся скорее к «современной волне тестирования», здесь же представлено нечто более «классическое» и привлекательное для любителей TDD или просто тех, кому необходимо писать юнит-тесты. Эта статья о том, КАК уменьшить количество моков (тестовых дублеров) в тестах. Не только потому, что написание моков влечет за собой расход ресурсов, но и потому, что они намекают на то, что что-то может быть не так. Другими словами, написание моков не является однозначно неверным решением, но большое количество моков является признаком того, что код далек от идеала. Подумайте о модуле, который наследуется от многих других, или о модуле, который взаимодействует с множеством других модулей для выполнения своей работы — тестирование и изменение такой структуры является тяжелым бременем:
«Моки необходимы, когда стратегия декомпозиции терпит неудачу».
Автор рассматривает различные приемы проектирования более автономных модулей, такие как:
— использование чистых функций, что поможет изолировать от остальной логики программы возможные побочные эффекты,
— использование pub/sub,
— изоляция ввода/вывода,
— объединение модулей с помощью паттернов, таких как монадические композиции, и др.
В целом тон статьи сбалансирован. В некоторых частях она поощряет функциональное программирование и методы, далекие от мейнстрима, поэтому читайте эти несколько частей с долей скептицизма.
Ссылка на статью: https://medium.com/javascript-scene/mocking-is-a-code-smell-944a70c90a6a
7. «Почему хорошие разработчики пишут плохие юнит-тесты» ***
Автор: Майкл Линч
11 мин (2,2000 слов), статья
Аннотация: Мне очень нравится эта статья. Автор наглядно показывает, как неожиданно иногда хорошие разработчики с прекрасными намерениями пишут плохие тесты:
Слишком часто разработчики ПО подходят к юнит-тестированию, руководствуясь одним и тем же ошибочным мышлением… Они механически применяют все «правила», которые они изучили за время написания продакшн кода, не проверяя, подходят ли они для тестов. В результате «строят небоскребы на пляже».
В статье на конкретных примерах кода показано, как ухудшается читаемость тестов при излишне сложном подходе, и как сохранить простоту. В одной из частей автор демонстрирует, как вдумчивое нарушение принципа DRY позволяет читателю оставаться внутри теста, сохраняя при этом поддерживаемость кода. Эта 11-минутная статья поможет значительно улучшить тесты, написанные разработчиками, которые склонны писать сложно. Если в вашей команде есть такой человек, вы теперь знаете, что делать.
Ссылка на статью: https://mtlynch.io/good-developers-bad-tests/
8. «Обзор тестирования JavaScript в 2022 году»
Автор: Виталий Зайдман
37 мин (7 400 слов), статья
Аннотация: эта статья уникальна тем, что в ней не рассматривается одна тема, а проводится обзор инструментов тестирования JavaScript. Это позволяет существенно обогатить свой инструментарий для любой ситуации. Например, знание о том, что существуют расширения IDE, которые показывают информацию о покрытии прямо в коде, может помочь вам повысить уровень внедрения тестов в команде. Знание о том, что существуют надежные, бесплатные и опенсорсные средства определения визуальной регрессии, может вдохновить вас глубже погрузиться в эту тему, и это лишь несколько примеров.
«Мы рассмотрели наиболее актуальные стратегии и инструменты тестирования в сообществе веб-разработчиков и, надеемся, облегчили вам тестирование сайтов. В конечном счете, наилучшие решения в отношении архитектуры приложений сегодня принимаются путем понимания общих закономерностей, модных в активном сообществе разработчиков, и сочетания их с собственным опытом и особенностями приложений».
В статье рассматриваются такие категории, как библиотеки для проверки утверждений, системы выполнения тестов, средства покрытия кода, средства определения визуальной регрессии, E2E тест-сьюты и многое другое.
Ссылка на статью: https://medium.com/welldone-software/an-overview-of-javascript-testing-7ce7298b9870
9. «Безопасный способ тестирования в продакшене»
Автор: Синди Сридхаран
54 мин (10 725 слов), статья
Аннотация: «Тестирование в продакшене» — это провокационный термин, который звучит как рискованный и безответственный подход к тестированию и противопоставляется предварительной проверке (еще один случай неудачной терминологии тестирования). На практике тестирование в продакшене не заменяет тестирования во время кодирования, а лишь добавляет дополнительный уровень уверенности за счет безопасного тестирования еще на трех этапах: деплой, релиз и пост-релиз. В этой обширной статье рассматриваются десятки методов. Некоторые из них необычны, например, traffic shadowing (паттерн деплоя, при котором трафик с продакшена асинхронно копируется и подается на сервисы для тестирования), tap compare (техника тестирования, позволяющая проверить поведение и производительность нового сервиса путем сравнения его результатов со старым сервисом) и т.д. Но главное, она иллюстрирует всесторонний процесс тестирования, начиная с компьютера разработчика и заканчивая версией, работающей у пользователей в продакшене.
Я все больше убеждаюсь в том, что промежуточные среды как моки — в лучшем случае это бледная имитация подлинного продукта, а в худшем — предвзятость подтверждения (confirmation bias).
Это все равно лучше, чем ничего — но состояние «работает на промежуточной среде» лишь на один шаг лучше, чем «работает на моей машине».
Ссылка на статью: https://copyconstruct.medium.com/testing-in-production-the-safe-way-18ca102d0ef1
10. «Please don’t mock me» (примеры на JavaScript, с JSConf) ***
Автор: Джастин Сёрлз
39 мин.
Аннотация: Это фантастическое выступление Justin Searls на JSConf US 2018 посвящено ахиллесовой пяте тестирования: где именно писать моки. Дилемма о том, где заканчивается область тестирования, что нужно имитировать, а что нет — это, пожалуй, наиболее стратегические решения в тест-дизайне. Рассмотрим модуль A, который взаимодействует с модулем B. Если изолировать A с помощью имитации B, то A всегда пройдет тест, даже если интерфейс B изменился, а код A не изменился вслед за ним. Это делает тесты A очень стабильными, но… продакшн упадет через несколько часов. В своем выступлении Джастин говорит:
«Тест, который никогда не бывает красным, — это плохой тест, потому что он ни о чем не говорит. Создавайте тесты так, чтобы они могли завершиться ошибкой.
Также он рассуждает о многих других интересных и непростых вопросах, связанных с мокингом, с прекрасными визуальными эффектами и массой идей. Не пропустите это выступление.
Ссылка на видео: https://www.youtube.com/watch?v=x8sKpJwq6lY&list=PL1CRgzydk3vzk5nMZNLTODfMartQQzInE&index=148
Автор оргинала: Yoni Goldberg
Источник: practica.dev
<!DOCTYPE html>
<html dir="ltr" lang="ru-RU">
<head>
<meta charset="UTF-8" />
<meta http-equiv="x-ua-compatible" content="ie=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="profile" href="http://gmpg.org/xfn/11" />
<title>Обеспечение качества: топ-10 статей OTUS</title>
<!-- All in One SEO 4.5.2.1 - aioseo.com -->
<meta name="description" content="Будучи консультантом по тестированию, я за годы работы прочитал массу статей по QA. Большинство из них — это в какой-то степени полезные, но часто случайные материалы, которые не всегда стоят времени. Но иногда я натыкался на удивительно хорошие, по моему мнению, статьи, которые действительно могут помочь улучшить навыки написания тестов. Я отобрал эти статьи и" />
<meta name="robots" content="max-image-preview:large" />
<link rel="canonical" href="https://otus.ru/journal/top-10-statej-po-testirovaniju/" />
<meta name="generator" content="All in One SEO (AIOSEO) 4.5.2.1" />
<script type="application/ld+json" class="aioseo-schema">
{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/otus.ru\/journal\/top-10-statej-po-testirovaniju\/#article","name":"\u041e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u0435 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0430: \u0442\u043e\u043f-10 \u0441\u0442\u0430\u0442\u0435\u0439 OTUS","headline":"\u041e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u0435 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0430: \u0442\u043e\u043f-10 \u0441\u0442\u0430\u0442\u0435\u0439","author":{"@id":"https:\/\/otus.ru\/journal\/author\/k-moseenkova\/#author"},"publisher":{"@id":"https:\/\/otus.ru\/journal\/#organization"},"image":{"@type":"ImageObject","url":"https:\/\/otus.ru\/journal\/wp-content\/uploads\/2023\/09\/oj-1080x720-kopiya-3.png","width":2245,"height":1587},"datePublished":"2023-09-14T09:26:56+00:00","dateModified":"2023-09-21T13:34:31+00:00","inLanguage":"ru-RU","mainEntityOfPage":{"@id":"https:\/\/otus.ru\/journal\/top-10-statej-po-testirovaniju\/#webpage"},"isPartOf":{"@id":"https:\/\/otus.ru\/journal\/top-10-statej-po-testirovaniju\/#webpage"},"articleSection":"\u041f\u0440\u043e IT, qa, \u043f\u043e\u0434\u0431\u043e\u0440\u043a\u0430, \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435"},{"@type":"BreadcrumbList","@id":"https:\/\/otus.ru\/journal\/top-10-statej-po-testirovaniju\/#breadcrumblist","itemListElement":[{"@type":"ListItem","@id":"https:\/\/otus.ru\/journal\/#listItem","position":1,"name":"\u0413\u043b\u0430\u0432\u043d\u0430\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0430","item":"https:\/\/otus.ru\/journal\/","nextItem":"https:\/\/otus.ru\/journal\/top-10-statej-po-testirovaniju\/#listItem"},{"@type":"ListItem","@id":"https:\/\/otus.ru\/journal\/top-10-statej-po-testirovaniju\/#listItem","position":2,"name":"\u041e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u0435 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0430: \u0442\u043e\u043f-10 \u0441\u0442\u0430\u0442\u0435\u0439","previousItem":"https:\/\/otus.ru\/journal\/#listItem"}]},{"@type":"Organization","@id":"https:\/\/otus.ru\/journal\/#organization","name":"\u041e\u0442\u0443\u0441 \u043e\u043d\u043b\u0430\u0439\u043d-\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u043d\u0438\u0435","url":"https:\/\/otus.ru\/journal\/","sameAs":["https:\/\/www.youtube.com\/channel\/UCetgtvy93o3i3CvyGXKFU3g"],"contactPoint":{"@type":"ContactPoint","telephone":"+74999389202","contactType":"Customer Support"}},{"@type":"Person","@id":"https:\/\/otus.ru\/journal\/author\/k-moseenkova\/#author","url":"https:\/\/otus.ru\/journal\/author\/k-moseenkova\/","name":"K. Moseenkova","image":{"@type":"ImageObject","@id":"https:\/\/otus.ru\/journal\/top-10-statej-po-testirovaniju\/#authorImage","url":"https:\/\/secure.gravatar.com\/avatar\/5bcd16ae9d4759f7841464ca0c13ba63?s=96&d=mm&r=g","width":96,"height":96,"caption":"K. Moseenkova"}},{"@type":"WebPage","@id":"https:\/\/otus.ru\/journal\/top-10-statej-po-testirovaniju\/#webpage","url":"https:\/\/otus.ru\/journal\/top-10-statej-po-testirovaniju\/","name":"\u041e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u0435 \u043a\u0430\u0447\u0435\u0441\u0442\u0432\u0430: \u0442\u043e\u043f-10 \u0441\u0442\u0430\u0442\u0435\u0439 OTUS","description":"\u0411\u0443\u0434\u0443\u0447\u0438 \u043a\u043e\u043d\u0441\u0443\u043b\u044c\u0442\u0430\u043d\u0442\u043e\u043c \u043f\u043e \u0442\u0435\u0441\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044e, \u044f \u0437\u0430 \u0433\u043e\u0434\u044b \u0440\u0430\u0431\u043e\u0442\u044b \u043f\u0440\u043e\u0447\u0438\u0442\u0430\u043b \u043c\u0430\u0441\u0441\u0443 \u0441\u0442\u0430\u0442\u0435\u0439 \u043f\u043e QA. \u0411\u043e\u043b\u044c\u0448\u0438\u043d\u0441\u0442\u0432\u043e \u0438\u0437 \u043d\u0438\u0445 \u2014 \u044d\u0442\u043e \u0432 \u043a\u0430\u043a\u043e\u0439-\u0442\u043e \u0441\u0442\u0435\u043f\u0435\u043d\u0438 \u043f\u043e\u043b\u0435\u0437\u043d\u044b\u0435, \u043d\u043e \u0447\u0430\u0441\u0442\u043e \u0441\u043b\u0443\u0447\u0430\u0439\u043d\u044b\u0435 \u043c\u0430\u0442\u0435\u0440\u0438\u0430\u043b\u044b, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043d\u0435 \u0432\u0441\u0435\u0433\u0434\u0430 \u0441\u0442\u043e\u044f\u0442 \u0432\u0440\u0435\u043c\u0435\u043d\u0438. \u041d\u043e \u0438\u043d\u043e\u0433\u0434\u0430 \u044f \u043d\u0430\u0442\u044b\u043a\u0430\u043b\u0441\u044f \u043d\u0430 \u0443\u0434\u0438\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u0445\u043e\u0440\u043e\u0448\u0438\u0435, \u043f\u043e \u043c\u043e\u0435\u043c\u0443 \u043c\u043d\u0435\u043d\u0438\u044e, \u0441\u0442\u0430\u0442\u044c\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0442\u0435\u043b\u044c\u043d\u043e \u043c\u043e\u0433\u0443\u0442 \u043f\u043e\u043c\u043e\u0447\u044c \u0443\u043b\u0443\u0447\u0448\u0438\u0442\u044c \u043d\u0430\u0432\u044b\u043a\u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u044f \u0442\u0435\u0441\u0442\u043e\u0432. \u042f \u043e\u0442\u043e\u0431\u0440\u0430\u043b \u044d\u0442\u0438 \u0441\u0442\u0430\u0442\u044c\u0438 \u0438","inLanguage":"ru-RU","isPartOf":{"@id":"https:\/\/otus.ru\/journal\/#website"},"breadcrumb":{"@id":"https:\/\/otus.ru\/journal\/top-10-statej-po-testirovaniju\/#breadcrumblist"},"author":{"@id":"https:\/\/otus.ru\/journal\/author\/k-moseenkova\/#author"},"creator":{"@id":"https:\/\/otus.ru\/journal\/author\/k-moseenkova\/#author"},"image":{"@type":"ImageObject","url":"https:\/\/otus.ru\/journal\/wp-content\/uploads\/2023\/09\/oj-1080x720-kopiya-3.png","@id":"https:\/\/otus.ru\/journal\/top-10-statej-po-testirovaniju\/#mainImage","width":2245,"height":1587},"primaryImageOfPage":{"@id":"https:\/\/otus.ru\/journal\/top-10-statej-po-testirovaniju\/#mainImage"},"datePublished":"2023-09-14T09:26:56+00:00","dateModified":"2023-09-21T13:34:31+00:00"},{"@type":"WebSite","@id":"https:\/\/otus.ru\/journal\/#website","url":"https:\/\/otus.ru\/journal\/","name":"OTUS JOURNAL","description":"Blog about IT","inLanguage":"ru-RU","publisher":{"@id":"https:\/\/otus.ru\/journal\/#organization"}}]}
</script>
<!-- All in One SEO -->
<link rel='dns-prefetch' href='//otus.ru' />
<link rel='dns-prefetch' href='//fonts.googleapis.com' />
<link rel='stylesheet' id='wp-block-library-css' href='https://otus.ru/journal/wp-includes/css/dist/block-library/style.min.css?ver=6.4.7' type='text/css' media='all' />
<style id='classic-theme-styles-inline-css' type='text/css'>
/*! This file is auto-generated */
.wp-block-button__link{color:#fff;background-color:#32373c;border-radius:9999px;box-shadow:none;text-decoration:none;padding:calc(.667em + 2px) calc(1.333em + 2px);font-size:1.125em}.wp-block-file__button{background:#32373c;color:#fff;text-decoration:none}
</style>
<style id='global-styles-inline-css' type='text/css'>
body{--wp--preset--color--black: #000000;--wp--preset--color--cyan-bluish-gray: #abb8c3;--wp--preset--color--white: #ffffff;--wp--preset--color--pale-pink: #f78da7;--wp--preset--color--vivid-red: #cf2e2e;--wp--preset--color--luminous-vivid-orange: #ff6900;--wp--preset--color--luminous-vivid-amber: #fcb900;--wp--preset--color--light-green-cyan: #7bdcb5;--wp--preset--color--vivid-green-cyan: #00d084;--wp--preset--color--pale-cyan-blue: #8ed1fc;--wp--preset--color--vivid-cyan-blue: #0693e3;--wp--preset--color--vivid-purple: #9b51e0;--wp--preset--gradient--vivid-cyan-blue-to-vivid-purple: linear-gradient(135deg,rgba(6,147,227,1) 0%,rgb(155,81,224) 100%);--wp--preset--gradient--light-green-cyan-to-vivid-green-cyan: linear-gradient(135deg,rgb(122,220,180) 0%,rgb(0,208,130) 100%);--wp--preset--gradient--luminous-vivid-amber-to-luminous-vivid-orange: linear-gradient(135deg,rgba(252,185,0,1) 0%,rgba(255,105,0,1) 100%);--wp--preset--gradient--luminous-vivid-orange-to-vivid-red: linear-gradient(135deg,rgba(255,105,0,1) 0%,rgb(207,46,46) 100%);--wp--preset--gradient--very-light-gray-to-cyan-bluish-gray: linear-gradient(135deg,rgb(238,238,238) 0%,rgb(169,184,195) 100%);--wp--preset--gradient--cool-to-warm-spectrum: linear-gradient(135deg,rgb(74,234,220) 0%,rgb(151,120,209) 20%,rgb(207,42,186) 40%,rgb(238,44,130) 60%,rgb(251,105,98) 80%,rgb(254,248,76) 100%);--wp--preset--gradient--blush-light-purple: linear-gradient(135deg,rgb(255,206,236) 0%,rgb(152,150,240) 100%);--wp--preset--gradient--blush-bordeaux: linear-gradient(135deg,rgb(254,205,165) 0%,rgb(254,45,45) 50%,rgb(107,0,62) 100%);--wp--preset--gradient--luminous-dusk: linear-gradient(135deg,rgb(255,203,112) 0%,rgb(199,81,192) 50%,rgb(65,88,208) 100%);--wp--preset--gradient--pale-ocean: linear-gradient(135deg,rgb(255,245,203) 0%,rgb(182,227,212) 50%,rgb(51,167,181) 100%);--wp--preset--gradient--electric-grass: linear-gradient(135deg,rgb(202,248,128) 0%,rgb(113,206,126) 100%);--wp--preset--gradient--midnight: linear-gradient(135deg,rgb(2,3,129) 0%,rgb(40,116,252) 100%);--wp--preset--font-size--small: 13px;--wp--preset--font-size--medium: 20px;--wp--preset--font-size--large: 36px;--wp--preset--font-size--x-large: 42px;--wp--preset--spacing--20: 0.44rem;--wp--preset--spacing--30: 0.67rem;--wp--preset--spacing--40: 1rem;--wp--preset--spacing--50: 1.5rem;--wp--preset--spacing--60: 2.25rem;--wp--preset--spacing--70: 3.38rem;--wp--preset--spacing--80: 5.06rem;--wp--preset--shadow--natural: 6px 6px 9px rgba(0, 0, 0, 0.2);--wp--preset--shadow--deep: 12px 12px 50px rgba(0, 0, 0, 0.4);--wp--preset--shadow--sharp: 6px 6px 0px rgba(0, 0, 0, 0.2);--wp--preset--shadow--outlined: 6px 6px 0px -3px rgba(255, 255, 255, 1), 6px 6px rgba(0, 0, 0, 1);--wp--preset--shadow--crisp: 6px 6px 0px rgba(0, 0, 0, 1);}:where(.is-layout-flex){gap: 0.5em;}:where(.is-layout-grid){gap: 0.5em;}body .is-layout-flow > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-flow > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-flow > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignleft{float: left;margin-inline-start: 0;margin-inline-end: 2em;}body .is-layout-constrained > .alignright{float: right;margin-inline-start: 2em;margin-inline-end: 0;}body .is-layout-constrained > .aligncenter{margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > :where(:not(.alignleft):not(.alignright):not(.alignfull)){max-width: var(--wp--style--global--content-size);margin-left: auto !important;margin-right: auto !important;}body .is-layout-constrained > .alignwide{max-width: var(--wp--style--global--wide-size);}body .is-layout-flex{display: flex;}body .is-layout-flex{flex-wrap: wrap;align-items: center;}body .is-layout-flex > *{margin: 0;}body .is-layout-grid{display: grid;}body .is-layout-grid > *{margin: 0;}:where(.wp-block-columns.is-layout-flex){gap: 2em;}:where(.wp-block-columns.is-layout-grid){gap: 2em;}:where(.wp-block-post-template.is-layout-flex){gap: 1.25em;}:where(.wp-block-post-template.is-layout-grid){gap: 1.25em;}.has-black-color{color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-color{color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-color{color: var(--wp--preset--color--white) !important;}.has-pale-pink-color{color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-color{color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-color{color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-color{color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-color{color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-color{color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-color{color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-color{color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-color{color: var(--wp--preset--color--vivid-purple) !important;}.has-black-background-color{background-color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-background-color{background-color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-background-color{background-color: var(--wp--preset--color--white) !important;}.has-pale-pink-background-color{background-color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-background-color{background-color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-background-color{background-color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-background-color{background-color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-background-color{background-color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-background-color{background-color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-background-color{background-color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-background-color{background-color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-background-color{background-color: var(--wp--preset--color--vivid-purple) !important;}.has-black-border-color{border-color: var(--wp--preset--color--black) !important;}.has-cyan-bluish-gray-border-color{border-color: var(--wp--preset--color--cyan-bluish-gray) !important;}.has-white-border-color{border-color: var(--wp--preset--color--white) !important;}.has-pale-pink-border-color{border-color: var(--wp--preset--color--pale-pink) !important;}.has-vivid-red-border-color{border-color: var(--wp--preset--color--vivid-red) !important;}.has-luminous-vivid-orange-border-color{border-color: var(--wp--preset--color--luminous-vivid-orange) !important;}.has-luminous-vivid-amber-border-color{border-color: var(--wp--preset--color--luminous-vivid-amber) !important;}.has-light-green-cyan-border-color{border-color: var(--wp--preset--color--light-green-cyan) !important;}.has-vivid-green-cyan-border-color{border-color: var(--wp--preset--color--vivid-green-cyan) !important;}.has-pale-cyan-blue-border-color{border-color: var(--wp--preset--color--pale-cyan-blue) !important;}.has-vivid-cyan-blue-border-color{border-color: var(--wp--preset--color--vivid-cyan-blue) !important;}.has-vivid-purple-border-color{border-color: var(--wp--preset--color--vivid-purple) !important;}.has-vivid-cyan-blue-to-vivid-purple-gradient-background{background: var(--wp--preset--gradient--vivid-cyan-blue-to-vivid-purple) !important;}.has-light-green-cyan-to-vivid-green-cyan-gradient-background{background: var(--wp--preset--gradient--light-green-cyan-to-vivid-green-cyan) !important;}.has-luminous-vivid-amber-to-luminous-vivid-orange-gradient-background{background: var(--wp--preset--gradient--luminous-vivid-amber-to-luminous-vivid-orange) !important;}.has-luminous-vivid-orange-to-vivid-red-gradient-background{background: var(--wp--preset--gradient--luminous-vivid-orange-to-vivid-red) !important;}.has-very-light-gray-to-cyan-bluish-gray-gradient-background{background: var(--wp--preset--gradient--very-light-gray-to-cyan-bluish-gray) !important;}.has-cool-to-warm-spectrum-gradient-background{background: var(--wp--preset--gradient--cool-to-warm-spectrum) !important;}.has-blush-light-purple-gradient-background{background: var(--wp--preset--gradient--blush-light-purple) !important;}.has-blush-bordeaux-gradient-background{background: var(--wp--preset--gradient--blush-bordeaux) !important;}.has-luminous-dusk-gradient-background{background: var(--wp--preset--gradient--luminous-dusk) !important;}.has-pale-ocean-gradient-background{background: var(--wp--preset--gradient--pale-ocean) !important;}.has-electric-grass-gradient-background{background: var(--wp--preset--gradient--electric-grass) !important;}.has-midnight-gradient-background{background: var(--wp--preset--gradient--midnight) !important;}.has-small-font-size{font-size: var(--wp--preset--font-size--small) !important;}.has-medium-font-size{font-size: var(--wp--preset--font-size--medium) !important;}.has-large-font-size{font-size: var(--wp--preset--font-size--large) !important;}.has-x-large-font-size{font-size: var(--wp--preset--font-size--x-large) !important;}
.wp-block-navigation a:where(:not(.wp-element-button)){color: inherit;}
:where(.wp-block-post-template.is-layout-flex){gap: 1.25em;}:where(.wp-block-post-template.is-layout-grid){gap: 1.25em;}
:where(.wp-block-columns.is-layout-flex){gap: 2em;}:where(.wp-block-columns.is-layout-grid){gap: 2em;}
.wp-block-pullquote{font-size: 1.5em;line-height: 1.6;}
</style>
<link rel='stylesheet' id='wbcr-comments-plus-url-span-css' href='https://otus.ru/journal/wp-content/plugins/clearfy/components/comments-plus/assets/css/url-span.css?ver=2.2.0' type='text/css' media='all' />
<link rel='stylesheet' id='wpel-style-css' href='https://otus.ru/journal/wp-content/plugins/wp-external-links/public/css/wpel.css?ver=2.59' type='text/css' media='all' />
<link rel='stylesheet' id='ez-toc-css' href='https://otus.ru/journal/wp-content/plugins/easy-table-of-contents/assets/css/screen.min.css?ver=2.0.61' type='text/css' media='all' />
<style id='ez-toc-inline-css' type='text/css'>
div#ez-toc-container .ez-toc-title {font-size: 120%;}div#ez-toc-container .ez-toc-title {font-weight: 500;}div#ez-toc-container ul li {font-size: 95%;}div#ez-toc-container nav ul ul li {font-size: 90%;}
.ez-toc-container-direction {direction: ltr;}.ez-toc-counter ul{counter-reset: item ;}.ez-toc-counter nav ul li a::before {content: counters(item, ".", decimal) ". ";display: inline-block;counter-increment: item;flex-grow: 0;flex-shrink: 0;margin-right: .2em; float: left; }.ez-toc-widget-direction {direction: ltr;}.ez-toc-widget-container ul{counter-reset: item ;}.ez-toc-widget-container nav ul li a::before {content: counters(item, ".", decimal) ". ";display: inline-block;counter-increment: item;flex-grow: 0;flex-shrink: 0;margin-right: .2em; float: left; }
</style>
<link rel='stylesheet' id='contentberg-fonts-css' href='https://fonts.googleapis.com/css?family=Roboto%3A400%2C500%2C700%7CPT+Serif%3A400%2C400i%2C600%7CIBM+Plex+Serif%3A500' type='text/css' media='all' />
<link rel='stylesheet' id='contentberg-core-css' href='https://otus.ru/journal/wp-content/themes/contentberg/style.css?ver=1.8.3' type='text/css' media='all' />
<link rel='stylesheet' id='contentberg-lightbox-css' href='https://otus.ru/journal/wp-content/themes/contentberg/css/lightbox.css?ver=1.8.3' type='text/css' media='all' />
<link rel='stylesheet' id='font-awesome-css' href='https://otus.ru/journal/wp-content/themes/contentberg/css/fontawesome/css/font-awesome.min.css?ver=1.8.3' type='text/css' media='all' />
<script type="text/javascript" id="breeze-prefetch-js-extra">
/* <![CDATA[ */
var breeze_prefetch = {"local_url":"https:\/\/otus.ru\/journal","ignore_remote_prefetch":"1","ignore_list":["\/wp-admin\/"]};
/* ]]> */
</script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/plugins/breeze/assets/js/js-front-end/breeze-prefetch-links.min.js" id="breeze-prefetch-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-includes/js/jquery/jquery.min.js" id="jquery-core-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-includes/js/jquery/jquery-migrate.min.js" id="jquery-migrate-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/themes/contentberg/js/lazysizes.js" id="lazysizes-js"></script>
<link rel="https://api.w.org/" href="https://otus.ru/journal/wp-json/" /><link rel="alternate" type="application/json" href="https://otus.ru/journal/wp-json/wp/v2/posts/7328" /><link rel='shortlink' href='https://otus.ru/journal/?p=7328' />
<link rel="alternate" type="application/json+oembed" href="https://otus.ru/journal/wp-json/oembed/1.0/embed?url=https%3A%2F%2Fotus.ru%2Fjournal%2Ftop-10-statej-po-testirovaniju%2F" />
<link rel="alternate" type="text/xml+oembed" href="https://otus.ru/journal/wp-json/oembed/1.0/embed?url=https%3A%2F%2Fotus.ru%2Fjournal%2Ftop-10-statej-po-testirovaniju%2F&format=xml" />
<script>var Sphere_Plugin = {"ajaxurl":"https:\/\/otus.ru\/journal\/wp-admin\/admin-ajax.php"};</script><link rel="icon" href="https://otus.ru/journal/wp-content/uploads/2020/11/cropped-OTUS_logo_OTUS-COMP-LOGO-WHITE-1-32x32.png" sizes="32x32" />
<link rel="icon" href="https://otus.ru/journal/wp-content/uploads/2020/11/cropped-OTUS_logo_OTUS-COMP-LOGO-WHITE-1-192x192.png" sizes="192x192" />
<link rel="apple-touch-icon" href="https://otus.ru/journal/wp-content/uploads/2020/11/cropped-OTUS_logo_OTUS-COMP-LOGO-WHITE-1-180x180.png" />
<meta name="msapplication-TileImage" content="https://otus.ru/journal/wp-content/uploads/2020/11/cropped-OTUS_logo_OTUS-COMP-LOGO-WHITE-1-270x270.png" />
<style type="text/css" id="wp-custom-css">
#menu-item-10406 .wpel-icon {
display: none;
}
#menu-item-10407 .wpel-icon {
display: none;
}
.otus-login-site a .wpel-icon {
display: none;
}
.menu-menju-navykov-container a .wpel-icon {
display: none;
}
.otus-login-site a
{
background: #ffd709;
border-radius: 12px;
color: #0f0f10;
font-size: 14px;
font-weight: 700;
line-height: 20px;
display: block;
text-align: center;
padding: 8px 25px;
}
.main-footer.dark {
background: linear-gradient(90deg, #a64fc5, #4f54e6);
border-color: transparent;
}
.main-footer.bold .copyright {
color: #fff;
}
.main-footer.bold .to-top i {
color: #fff;
}
.main-footer.bold .back-to-top {
color: #fff;
}
.nav__scroll {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
.scrollable-menu .menu {
display: flex;
}
.nav__scroll
{
background: linear-gradient(90deg, #a64fc5, #4f54e6);
}
.scrollable-menu .menu .menu-item {
flex: 0 0 auto;
padding: 15px 15px;
}
.scrollable-menu .menu .menu-item a {
color: #fff;
}
.nav__scroll::-webkit-scrollbar{background-color:#fff;height:5px;}
.nav__scroll::-webkit-scrollbar-thumb{background-color:#dcdcdc;}
.nav__scroll::-webkit-scrollbar-track{-webkit-border-radius:0;border-radius:0;background-color:#fff;}/
body {
min-width: 320px;
}
.banner-click img {
margin: 0 auto;
display: block;
}
.banner-click {
cursor: pointer;
}
.banner-footer-area {
margin-bottom: 20px;
}
.banner-left-area {
margin-top: 40px;
} </style>
<!--Start VDZ Yandex Metrika Plugin-->
<!-- Yandex.Metrika counter --><script type="text/javascript" >(function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};m[i].l=1*new Date();k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)})(window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym");ym(34531570, "init", {clickmap:true, trackLinks:true, accurateTrackBounce:true, webvisor:true, trackHash:true, ecommerce:"dataLayer"});</script>
<noscript><div><img src="https://mc.yandex.ru/watch/34531570" style="position:absolute; left:-9999px;" alt="" /></div></noscript>
<!-- /Yandex.Metrika counter --><!--START ADD EVENTS FROM CF7--><script type='text/javascript'>document.addEventListener( 'wpcf7submit', function( event ) {
//event.detail.contactFormId;
if(ym){
//console.log(event.detail);
ym(34531570, 'reachGoal', 'VDZ_SEND_CONTACT_FORM_7');
ym(34531570, 'params', {
page_url: window.location.href,
status: event.detail.status,
locale: event.detail.contactFormLocale,
form_id: event.detail.contactFormId,
});
}
}, false );
</script><!--END ADD EVENTS FROM CF7-->
<!--End VDZ Yandex Metrika Plugin-->
</head>
<body class="post-template-default single single-post postid-7328 single-format-standard right-sidebar lazy-normal has-lb">
<div class="main-wrap">
<header id="main-head" class="main-head head-nav-below has-search-modal simple simple-boxed">
<div class="inner inner-head" data-sticky-bar="0">
<div class="wrap cf wrap-head">
<div class="left-contain">
<span class="mobile-nav"><i class="fa fa-bars"></i></span>
<div class="title">
<a href="https://otus.ru/journal/" title="OTUS JOURNAL" rel="home" data-wpel-link="internal">
<span class="text-logo"><img src="/journal/wp-content/themes/contentberg/img/logo_site.svg" alt="OTUS JOURNAL"></span>
</a>
</div>
</div>
<div class="navigation-wrap inline">
<nav class="navigation inline simple light" data-sticky-bar="0">
<div class="menu-rubriki-container"><ul id="menu-rubriki" class="menu"><li id="menu-item-109" class="menu-item menu-item-type-taxonomy menu-item-object-category current-post-ancestor current-menu-parent current-post-parent menu-cat-1 menu-item-109"><a href="https://otus.ru/journal/category/pro-it/" data-wpel-link="internal"><span>Про IT</span></a></li>
<li id="menu-item-113" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-cat-4 menu-item-113"><a href="https://otus.ru/journal/category/polza/" data-wpel-link="internal"><span>Полезное</span></a></li>
<li id="menu-item-114" class="menu-item menu-item-type-taxonomy menu-item-object-category menu-cat-3 menu-item-114"><a href="https://otus.ru/journal/category/lifestyle/" data-wpel-link="internal"><span>Лайфстайл</span></a></li>
<li id="menu-item-10406" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10406"><a href="https://otus.ru/catalog/courses" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right"><span>Обучение</span><span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li id="menu-item-10407" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10407"><a href="https://otus.ru/about" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right"><span>Информация</span><span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
</ul></div> </nav>
</div>
<div class="actions">
<div class="otus-login-site">
<a href="https://otus.ru/login/" target="_blank" data-wpel-link="external" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Войти<span class="wpel-icon wpel-image wpel-icon-6"></span></a>
</div>
<a href="#" title="Search" class="search-link"><i class="fa fa-search"></i></a>
</div>
</div>
</div>
</header> <!-- .main-head -->
<div class="nav nav_disable nav_colored nav_transparent course-categories__nav nav__scroll ">
<div class="container wrap">
<div class="links inline simple light scrollable-menu">
<div class="menu-menju-navykov-container"><ul id="menu-menju-navykov" class="menu"><li id="menu-item-10413" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10413"><a href="https://otus.ru/categories/programming/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Программирование<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li id="menu-item-10414" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10414"><a href="https://otus.ru/categories/architecture/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Архитектура<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li id="menu-item-10415" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10415"><a href="https://otus.ru/categories/operations/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Инфраструктура<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li id="menu-item-10416" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10416"><a href="https://otus.ru/categories/information-security-courses/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Безопасность<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li id="menu-item-10417" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10417"><a href="https://otus.ru/categories/data-science/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Data Science<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li id="menu-item-10418" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10418"><a href="https://otus.ru/categories/gamedev/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">GameDev<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li id="menu-item-10419" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10419"><a href="https://otus.ru/categories/marketing-business/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Управление<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li id="menu-item-10420" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10420"><a href="https://otus.ru/categories/analytics/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Аналитика и анализ<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li id="menu-item-10421" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10421"><a href="https://otus.ru/categories/testing/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Тестирование<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
</ul></div> </div>
</div>
</div>
<div class="main wrap">
<div class="ts-row cf">
<div class="col-8 main-content cf">
<article id="post-7328" class="the-post post-7328 post type-post status-publish format-standard has-post-thumbnail category-pro-it tag-qa tag-podborka tag-testirovanie">
<header class="post-header the-post-header cf">
<div class="post-meta the-post-meta">
<span class="post-cat">
<a href="https://otus.ru/journal/category/pro-it/" class="category" data-wpel-link="internal">Про IT</a>
</span>
<h1 class="post-title">
Обеспечение качества: топ-10 статей
</h1>
<a href="https://otus.ru/journal/top-10-statej-po-testirovaniju/" class="date-link" data-wpel-link="internal"><time class="post-date">14 сентября, 2023</time></a>
</div>
</header><!-- .post-header -->
<div class="post-content description cf entry-content content-normal">
<div id="ez-toc-container" class="ez-toc-v2_0_61 counter-hierarchy ez-toc-counter ez-toc-grey ez-toc-container-direction">
<div class="ez-toc-title-container">
<p class="ez-toc-title " >Содержание</p>
<span class="ez-toc-title-toggle"><a href="#" class="ez-toc-pull-right ez-toc-btn ez-toc-btn-xs ez-toc-btn-default ez-toc-toggle" aria-label="Toggle Table of Content"><span class="ez-toc-js-icon-con"><span class=""><span class="eztoc-hide" style="display:none;">Toggle</span><span class="ez-toc-icon-toggle-span"><svg style="fill: #999;color:#999" xmlns="http://www.w3.org/2000/svg" class="list-377408" width="20px" height="20px" viewBox="0 0 24 24" fill="none"><path d="M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z" fill="currentColor"></path></svg><svg style="fill: #999;color:#999" class="arrow-unsorted-368013" xmlns="http://www.w3.org/2000/svg" width="10px" height="10px" viewBox="0 0 24 24" version="1.2" baseProfile="tiny"><path d="M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z"/></svg></span></span></span></a></span></div>
<nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class="ez-toc-link ez-toc-heading-1" href="#1_%C2%AB%D0%92%D1%8B%D0%B1%D0%BE%D1%80%D0%BE%D1%87%D0%BD%D0%BE%D0%B5_%D1%8E%D0%BD%D0%B8%D1%82-%D1%82%D0%B5%D1%81%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%E2%80%94_%D0%BF%D0%BB%D1%8E%D1%81%D1%8B_%D0%B8_%D0%BC%D0%B8%D0%BD%D1%83%D1%81%D1%8B%C2%BB" title="1. «Выборочное юнит-тестирование — плюсы и минусы»">1. «Выборочное юнит-тестирование — плюсы и минусы»</a></li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class="ez-toc-link ez-toc-heading-2" href="#2_%C2%AB%D0%A2%D0%B5%D1%81%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%B4%D0%B5%D1%82%D0%B0%D0%BB%D0%B5%D0%B9_%D1%80%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8%C2%BB_%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D1%80_%D0%BD%D0%B0_JavaScript" title="2. «Тестирование деталей реализации» (пример на JavaScript)">2. «Тестирование деталей реализации» (пример на JavaScript)</a></li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class="ez-toc-link ez-toc-heading-3" href="#3_%C2%AB%D0%A0%D0%B0%D0%B7%D1%83%D0%BC%D0%BD%D1%8B%D0%B9_%D1%81%D0%BF%D0%BE%D1%81%D0%BE%D0%B1_%D1%82%D0%B5%D1%81%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_%D0%BC%D0%B8%D0%BA%D1%80%D0%BE%D1%81%D0%B5%D1%80%D0%B2%D0%B8%D1%81%D0%BE%D0%B2%C2%BB" title="3. «Разумный способ тестирования микросервисов» ***">3. «Разумный способ тестирования микросервисов» ***</a></li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class="ez-toc-link ez-toc-heading-4" href="#4_%C2%AB%D0%9A%D0%B0%D0%BA_%D0%BF%D1%80%D0%BE%D0%B2%D0%BE%D0%B4%D0%B8%D1%82%D1%8C_%D1%8E%D0%BD%D0%B8%D1%82-%D1%82%D0%B5%D1%81%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D1%81_Nodejs%C2%BB_%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D1%8B_%D0%BD%D0%B0_JavaScript_%D0%B4%D0%BB%D1%8F_%D0%BD%D0%B0%D1%87%D0%B8%D0%BD%D0%B0%D1%8E%D1%89%D0%B8%D1%85" title="4. «Как проводить юнит-тестирование с Node.js?» (примеры на JavaScript, для начинающих)">4. «Как проводить юнит-тестирование с Node.js?» (примеры на JavaScript, для начинающих)</a></li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class="ez-toc-link ez-toc-heading-5" href="#5_%C2%AB%D0%A4%D0%B5%D1%82%D0%B8%D1%88_%D1%8E%D0%BD%D0%B8%D1%82-%D1%82%D0%B5%D1%81%D1%82%D0%BE%D0%B2%C2%BB" title="5. «Фетиш юнит-тестов»">5. «Фетиш юнит-тестов»</a></li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class="ez-toc-link ez-toc-heading-6" href="#6_%C2%AB%D0%9D%D0%B0%D0%BB%D0%B8%D1%87%D0%B8%D0%B5_%D0%BC%D0%BE%D0%BA%D0%BE%D0%B2_%E2%80%94_%D1%8D%D1%82%D0%BE_%D0%BF%D1%80%D0%B8%D0%B7%D0%BD%D0%B0%D0%BA_%D0%BF%D0%BB%D0%BE%D1%85%D0%BE%D0%B3%D0%BE_%D0%BA%D0%BE%D0%B4%D0%B0%C2%BB_%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D1%8B_%D0%BD%D0%B0_JavaScript" title="6. «Наличие моков — это признак плохого кода» (примеры на JavaScript)">6. «Наличие моков — это признак плохого кода» (примеры на JavaScript)</a></li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class="ez-toc-link ez-toc-heading-7" href="#7_%C2%AB%D0%9F%D0%BE%D1%87%D0%B5%D0%BC%D1%83_%D1%85%D0%BE%D1%80%D0%BE%D1%88%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%87%D0%B8%D0%BA%D0%B8_%D0%BF%D0%B8%D1%88%D1%83%D1%82_%D0%BF%D0%BB%D0%BE%D1%85%D0%B8%D0%B5_%D1%8E%D0%BD%D0%B8%D1%82-%D1%82%D0%B5%D1%81%D1%82%D1%8B%C2%BB" title="7. «Почему хорошие разработчики пишут плохие юнит-тесты» *** ">7. «Почему хорошие разработчики пишут плохие юнит-тесты» *** </a></li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class="ez-toc-link ez-toc-heading-8" href="#8_%C2%AB%D0%9E%D0%B1%D0%B7%D0%BE%D1%80_%D1%82%D0%B5%D1%81%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_JavaScript_%D0%B2_2022_%D0%B3%D0%BE%D0%B4%D1%83%C2%BB" title="8. «Обзор тестирования JavaScript в 2022 году» ">8. «Обзор тестирования JavaScript в 2022 году» </a></li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class="ez-toc-link ez-toc-heading-9" href="#9_%C2%AB%D0%91%D0%B5%D0%B7%D0%BE%D0%BF%D0%B0%D1%81%D0%BD%D1%8B%D0%B9_%D1%81%D0%BF%D0%BE%D1%81%D0%BE%D0%B1_%D1%82%D0%B5%D1%81%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_%D0%B2_%D0%BF%D1%80%D0%BE%D0%B4%D0%B0%D0%BA%D1%88%D0%B5%D0%BD%D0%B5%C2%BB" title="9. «Безопасный способ тестирования в продакшене»">9. «Безопасный способ тестирования в продакшене»</a></li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class="ez-toc-link ez-toc-heading-10" href="#10_%C2%ABPlease_dont_mock_me%C2%BB_%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D1%8B_%D0%BD%D0%B0_JavaScript_%D1%81_JSConf" title="10. «Please don’t mock me» (примеры на JavaScript, с JSConf) ***">10. «Please don’t mock me» (примеры на JavaScript, с JSConf) ***</a></li></ul></nav></div>
<p>Будучи консультантом по тестированию, я за годы работы прочитал массу статей по QA. Большинство из них — это в какой-то степени полезные, но часто случайные материалы, которые не всегда стоят времени. Но иногда я натыкался на удивительно хорошие, по моему мнению, статьи, которые действительно могут помочь улучшить навыки написания тестов. Я отобрал эти статьи и написал к ним аннотации. Половина из них относится непосредственно к JavaScript/Node.js, вторая половина охватывает общие концепции тестирования, которые применимы в любом языке.</p>
<p>Почему эти статьи показались мне выдающимися? Во-первых, они отлично написаны. Во-вторых, они посвящены «новому миру тестирования» — не общеизвестным «TDD-шным» вещам, а современным концепциям и инструментам.</p>
<p>Если вы слишком заняты, чтобы прочитать их все, то ищите статьи, отмеченные тремя звездочками *** — это шедевры, которые ни в коем случае нельзя пропускать.</p>
<h2 class="wp-block-heading"><span class="ez-toc-section" id="1_%C2%AB%D0%92%D1%8B%D0%B1%D0%BE%D1%80%D0%BE%D1%87%D0%BD%D0%BE%D0%B5_%D1%8E%D0%BD%D0%B8%D1%82-%D1%82%D0%B5%D1%81%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%E2%80%94_%D0%BF%D0%BB%D1%8E%D1%81%D1%8B_%D0%B8_%D0%BC%D0%B8%D0%BD%D1%83%D1%81%D1%8B%C2%BB"></span>1. «Выборочное юнит-тестирование — плюсы и минусы»<span class="ez-toc-section-end"></span></h2>
<p>Автор: Стив Сандерсон (Steve Sanderson)<br>9 мин (1850 слов), <a href="https://blog.stevensanderson.com/2009/11/04/selective-unit-testing-costs-and-benefits/" target="_blank" rel="noopener nofollow external noreferrer" title="статья" data-wpel-link="external" class="wpel-icon-right">статья<span class="wpel-icon wpel-image wpel-icon-6"></span></a></p>
<p>Аннотация: Все мы хотя бы раз участвовали в оживленной дискуссии о «юнитах» и «интеграции». В этой статье автор выходит на более высокий уровень конкретики и рассуждает о том, КОГДА юнит-тесты хороши, рассмотрев затраты на написание этих тестов в <em>различных сценариях</em>. Многие относятся к своей стратегии тестирования как к статической модели — технике тестирования, к которой они прибегают всегда, независимо от контекста. «Всегда пишите юнит-тесты на функции», «Пишите в основном интеграционные тесты» — такие аргументы часто можно услышать. В данной статье, напротив, предлагается оценивать целесообразности юнит-тестов, исходя из <em>затрат на модуль и выгод</em>. В статье классифицируется несколько сценариев, в которых чистая ценность юнит-тестов высока или низка, например:</p>
<p>Если ваш код в принципе очевиден — то есть с первого взгляда понятно, что именно он делает, — то дополнительное проектирование и верификация приносят крайне минимальную пользу.</p>
<p>Автор также использует модель 2×2 для визуализации того, когда привлекательность юнит -тестов высока или низка:</p>
<figure class="wp-block-image"><img decoding="async" src="https://lh5.googleusercontent.com/b8zoA_XO5Eqf5CUMgGvUpZUl8YO7kp0L2xzps-GXkhHkLlKtlZkpt58RU1H1gi93VIOVPSf_k18SuGd1dFr8Orm6YYediU34dGzbEt38DbziS8wo732kmhOQeU5cEuu0dXXrCWyjaFOhldQiWeXQIm8" alt="When unit shines"/></figure>
<p>Примечание, не относящееся к статье: лично я (Йони) всегда начинаю с компонентных тестов, охватывая сначала высокоуровневые детали пути пользователя (так называемый <a href="https://www.crispy-engineering.com/p/why-test-diamond-model-makes-sense" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">ромб тестирования<span class="wpel-icon wpel-image wpel-icon-6"></span></a>). Затем, когда появляются функции, я добавляю юнит-тесты, основываясь на их чистой ценности. Эта статья помогла мне классифицировать и оценить преимущества юнит-тестов в различных сценариях.</p>
<p>Ссылка на статью: <a href="https://blog.stevensanderson.com/2009/11/04/selective-unit-testing-costs-and-benefits/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">https://blog.stevensanderson.com/2009/11/04/selective-unit-testing-costs-and-benefits/<span class="wpel-icon wpel-image wpel-icon-6"></span></a></p>
<hr class="wp-block-separator has-alpha-channel-opacity"/>
<h2 class="wp-block-heading"><span class="ez-toc-section" id="2_%C2%AB%D0%A2%D0%B5%D1%81%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D0%B4%D0%B5%D1%82%D0%B0%D0%BB%D0%B5%D0%B9_%D1%80%D0%B5%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D0%B8%C2%BB_%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D1%80_%D0%BD%D0%B0_JavaScript"></span>2. «Тестирование деталей реализации» (пример на JavaScript)<span class="ez-toc-section-end"></span></h2>
<p>Автор: Kent C Dodds (Kent C Dodds)<br>13 мин (2600 слов), <a href="https://kentcdodds.com/blog/testing-implementation-details" target="_blank" rel="noopener nofollow external noreferrer" title="статья" data-wpel-link="external" class="wpel-icon-right">статья<span class="wpel-icon wpel-image wpel-icon-6"></span></a></p>
<p>Аннотация: Автор на примере кода описывает неизбежную трагичность веры тестировщика, который делает ставку на детали реализации. Если не принимать во внимание усилия, затрачиваемые на тестирование такого количества деталей, то такой путь всегда заканчивается «ложноположительными» и «ложноотрицательными» результатами. Это ставит под сомнение надежность тестов. Статья иллюстрирует этот тезис на примере фронтенд-кода, но выводы из урока универсальны для любого вида тестирования.</p>
<p>«Есть две причины, почему важно избегать тестирования деталей реализации. Тесты, проверяющие детали реализации:</p>
<ol>
<li>Могут сломаться при рефакторинге кода приложения. <em>Ложноотрицательные результаты</em></li>
<li>Могут не сработать, когда вы ломаете код приложения. <em>Ложноположительные результаты</em>».</li>
</ol>
<p>Ссылка на статью: <a href="https://kentcdodds.com/blog/testing-implementation-details" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">https://kentcdodds.com/blog/testing-implementation-details<span class="wpel-icon wpel-image wpel-icon-6"></span></a> </p>
<p>p.s. У этого автора есть еще одна замечательная статья о современной стратегии тестирования — «<a href="https://kentcdodds.com/blog/write-tests" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Пишите тесты. Не слишком много. В основном интеграционные<span class="wpel-icon wpel-image wpel-icon-6"></span></a>».</p>
<hr class="wp-block-separator has-alpha-channel-opacity"/>
<h2 class="wp-block-heading"><span class="ez-toc-section" id="3_%C2%AB%D0%A0%D0%B0%D0%B7%D1%83%D0%BC%D0%BD%D1%8B%D0%B9_%D1%81%D0%BF%D0%BE%D1%81%D0%BE%D0%B1_%D1%82%D0%B5%D1%81%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_%D0%BC%D0%B8%D0%BA%D1%80%D0%BE%D1%81%D0%B5%D1%80%D0%B2%D0%B8%D1%81%D0%BE%D0%B2%C2%BB"></span>3. «Разумный способ тестирования микросервисов» ***<span class="ez-toc-section-end"></span></h2>
<p>Автор: Синди Сридхаран<br>Время чтения: > 2 часов (10 500 слов с большим количеством ссылок), <a href="https://copyconstruct.medium.com/testing-microservices-the-sane-way-9bb31d158c16" target="_blank" rel="noopener nofollow external noreferrer" title="статья" data-wpel-link="external" class="wpel-icon-right">статья<span class="wpel-icon wpel-image wpel-icon-6"></span></a></p>
<p>Аннотация: Это целая библия по тестированию микросервисов и современного распределенного тестирования, упакованная в одну длинную увлекательную статью. Помню, когда я наткнулся на нее четыре года назад, я каждый день перед сном проводил час с улыбкой на лице, читая ее. Я внимательно переходил по каждой ссылке, делал паузу после каждого абзаца, чтобы подумать — передо мной открывался совершенно новый мир. Это было настолько увлекательно, что мне захотелось специализироваться в этой области. Спустя годы это стало основной часть моей работы, и я наслаждаюсь каждым моментом.</p>
<p>Эта статья начинается с объяснения, почему E2E и юнит-тесты не оправдывают ожиданий в распределенной среде. А также почему любого вида закодированных тестов будет недостаточно, а необходим богатый набор методик. В статье рассматривается ряд современных методов тестирования, незнакомых большинству разработчиков. Одна из ключевых частей книги посвящена тому, что должно быть канонической техникой тестирования у разработчиков: автор выступает за «большие юнит-тесты» (т.е. компонентные тесты), поскольку они обеспечивают баланс между удобством для разработчиков и реалистичностью.</p>
<p>Я придумал термин «step-up testing», общая идея которого заключается в том, чтобы тестировать на один уровень выше того, что обычно пропагандируется. Согласно этой модели, юнит-тесты будут больше походить на интеграционные (рассматривая ввод/вывод как часть тестируемого модуля в ограниченном контексте), интеграционное тестирование будет больше походить на тестирование в продакшене, а тестирование в продакшене будет больше походить на мониторинг и исследование. Реорганизованная тестовая пирамида (тестовая воронка) для распределенных систем будет выглядеть следующим образом:</p>
<figure class="wp-block-image"><img decoding="async" src="https://lh5.googleusercontent.com/swF3_ptXLFyOyXnOTGNYiIgsEgNT7KFRfyk9zTAElJoqW1diBxJFMVjx4DsRSTZaGzSBf96Eq8Rd806EQZjLaoOvm3BbT8eQpN2jQIswXxlQGnDqg27wHQc-zCjBCqnLmEc4369Vq6mwW1LV7ZdeDCo" alt="When unit shines"/></figure>
<p>Вне зависимости от того, с каким типом системы вы имеете дело, эта статья расширит ваш взгляд на тестирование и подарит множество новых идей.</p>
<p>Ссылка на статью: <a href="https://copyconstruct.medium.com/testing-microservices-the-sane-way-9bb31d158c16" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">https://copyconstruct.medium.com/testing-microservices-the-sane-way-9bb31d158c16<span class="wpel-icon wpel-image wpel-icon-6"></span></a> </p>
<hr class="wp-block-separator has-alpha-channel-opacity"/>
<h2 class="wp-block-heading"><span class="ez-toc-section" id="4_%C2%AB%D0%9A%D0%B0%D0%BA_%D0%BF%D1%80%D0%BE%D0%B2%D0%BE%D0%B4%D0%B8%D1%82%D1%8C_%D1%8E%D0%BD%D0%B8%D1%82-%D1%82%D0%B5%D1%81%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5_%D1%81_Nodejs%C2%BB_%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D1%8B_%D0%BD%D0%B0_JavaScript_%D0%B4%D0%BB%D1%8F_%D0%BD%D0%B0%D1%87%D0%B8%D0%BD%D0%B0%D1%8E%D1%89%D0%B8%D1%85"></span>4. «Как проводить юнит-тестирование с Node.js?» (примеры на JavaScript, для начинающих)<span class="ez-toc-section-end"></span></h2>
<p>Автор: Райан Джонс (Ryan Jones)<br>16 мин (3000 слов), <a href="https://medium.com/serverlessguru/how-to-unit-test-with-nodejs-76967019ba56" target="_blank" rel="noopener nofollow external noreferrer" title="статья" data-wpel-link="external" class="wpel-icon-right">статья<span class="wpel-icon wpel-image wpel-icon-6"></span></a></p>
<p>Аннотация: это единственная статья из списка, подходящая новичкам в тестировании.<em> </em></p>
<p>Это руководство я выбрал из множества других вариантов потому, что оно относительно полное и хорошо написано. В нем рассматриваются шаги, о которых новичку следует узнать в первую очередь: интерфейс программ для запуска тестов, CLI программы Test Runners, проверка утверждений и асинхронные тесты. Разумеется, этих знаний будет недостаточно для того, чтобы покрыть тестами реальное приложение, но они позволят благополучно перейти к следующему этапу. Мой личный совет: после прочтения этой статьи стоит перейти к изучению тестовых дублеров (моков).</p>
<p>Ссылка на статью: <a href="https://medium.com/serverlessguru/how-to-unit-test-with-nodejs-76967019ba56" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">https://medium.com/serverlessguru/how-to-unit-test-with-nodejs-76967019ba56<span class="wpel-icon wpel-image wpel-icon-6"></span></a> </p>
<hr class="wp-block-separator has-alpha-channel-opacity"/>
<h2 class="wp-block-heading"><span class="ez-toc-section" id="5_%C2%AB%D0%A4%D0%B5%D1%82%D0%B8%D1%88_%D1%8E%D0%BD%D0%B8%D1%82-%D1%82%D0%B5%D1%81%D1%82%D0%BE%D0%B2%C2%BB"></span>5. «Фетиш юнит-тестов»<span class="ez-toc-section-end"></span></h2>
<p>Автор: Мартин Сустрик<br>5 мин (1000 слов), <a href="https://250bpm.com/blog:40/" target="_blank" rel="noopener nofollow external noreferrer" title="статья" data-wpel-link="external" class="wpel-icon-right">статья<span class="wpel-icon wpel-image wpel-icon-6"></span></a></p>
<p>Аннотация: Статья начинается словами: «Я слышал, что в наши дни люди испытывают неконтролируемое желание писать юнит-тесты. Если вы один из них, потратьте несколько минут на изучение причин, по которым писать юнит-тесты НЕЛЬЗЯ». Несмотря на такое неоднозначное вступление, автор статьи не выступает против юнит-тестов как таковых, а скорее подчеркивает, когда и где юнит-тесты оказываются неэффективными. В этих случаях следует рассмотреть другие методы. Вот пример: Юнит-тесты по своей природе имеют более низкий ROI (return on investment, рентабельность вложений), и автор приводит звучную метафору: «Приступая к покраске дома, вы начинаете с самой большой кисти, а маленькую кисть оставляете на конец, чтобы разобраться с мелкими деталями». Начиная свою работу по QA с юнит-тестов, вы, по сути, пытаетесь расписать весь дом самой тонкой китайской кисточкой для каллиграфии…».</p>
<p>Ссылка на статью: <a href="https://250bpm.com/blog:40/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">https://250bpm.com/blog:40/<span class="wpel-icon wpel-image wpel-icon-6"></span></a> </p>
<hr class="wp-block-separator has-alpha-channel-opacity"/>
<h2 class="wp-block-heading"><span class="ez-toc-section" id="6_%C2%AB%D0%9D%D0%B0%D0%BB%D0%B8%D1%87%D0%B8%D0%B5_%D0%BC%D0%BE%D0%BA%D0%BE%D0%B2_%E2%80%94_%D1%8D%D1%82%D0%BE_%D0%BF%D1%80%D0%B8%D0%B7%D0%BD%D0%B0%D0%BA_%D0%BF%D0%BB%D0%BE%D1%85%D0%BE%D0%B3%D0%BE_%D0%BA%D0%BE%D0%B4%D0%B0%C2%BB_%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D1%8B_%D0%BD%D0%B0_JavaScript"></span>6. «Наличие моков — это признак плохого кода» (примеры на JavaScript)<span class="ez-toc-section-end"></span></h2>
<p>Автор: Эрик Эллиотт<br>32 мин (6 300 слов), <a href="https://medium.com/javascript-scene/mocking-is-a-code-smell-944a70c90a6a" target="_blank" rel="noopener nofollow external noreferrer" title="статья" data-wpel-link="external" class="wpel-icon-right">статья<span class="wpel-icon wpel-image wpel-icon-6"></span></a></p>
<p>Аннотация: Большинство статей из этого списка относятся скорее к «современной волне тестирования», здесь же представлено нечто более «классическое» и привлекательное для любителей TDD или просто тех, кому необходимо писать юнит-тесты. Эта статья о том, КАК уменьшить количество моков (тестовых дублеров) в тестах. Не только потому, что написание моков влечет за собой расход ресурсов, но и потому, что они намекают на то, что что-то может быть не так. Другими словами, написание моков не является однозначно неверным решением, но <em>большое</em> количество моков является признаком того, что код далек от идеала. Подумайте о модуле, который наследуется от многих других, или о модуле, который взаимодействует с множеством других модулей для выполнения своей работы — тестирование и изменение такой структуры является тяжелым бременем:</p>
<p>«Моки необходимы, когда стратегия декомпозиции терпит неудачу».</p>
<p>Автор рассматривает различные приемы проектирования более автономных модулей, такие как:<br>— использование чистых функций, что поможет изолировать от остальной логики программы возможные побочные эффекты,<br>— использование pub/sub,<br>— изоляция ввода/вывода,<br>— объединение модулей с помощью паттернов, таких как монадические композиции, и др.</p>
<p>В целом тон статьи сбалансирован. В некоторых частях она поощряет функциональное программирование и методы, далекие от мейнстрима, поэтому читайте эти несколько частей с долей скептицизма.</p>
<p>Ссылка на статью: <a href="https://medium.com/javascript-scene/mocking-is-a-code-smell-944a70c90a6a" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">https://medium.com/javascript-scene/mocking-is-a-code-smell-944a70c90a6a<span class="wpel-icon wpel-image wpel-icon-6"></span></a></p>
<hr class="wp-block-separator has-alpha-channel-opacity"/>
<h2 class="wp-block-heading"><span class="ez-toc-section" id="7_%C2%AB%D0%9F%D0%BE%D1%87%D0%B5%D0%BC%D1%83_%D1%85%D0%BE%D1%80%D0%BE%D1%88%D0%B8%D0%B5_%D1%80%D0%B0%D0%B7%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D1%87%D0%B8%D0%BA%D0%B8_%D0%BF%D0%B8%D1%88%D1%83%D1%82_%D0%BF%D0%BB%D0%BE%D1%85%D0%B8%D0%B5_%D1%8E%D0%BD%D0%B8%D1%82-%D1%82%D0%B5%D1%81%D1%82%D1%8B%C2%BB"></span>7. «Почему хорошие разработчики пишут плохие юнит-тесты» *** <span class="ez-toc-section-end"></span></h2>
<p>Автор: Майкл Линч<br>11 мин (2,2000 слов), <a href="https://mtlynch.io/good-developers-bad-tests/" target="_blank" rel="noopener nofollow external noreferrer" title="статья" data-wpel-link="external" class="wpel-icon-right">статья<span class="wpel-icon wpel-image wpel-icon-6"></span></a></p>
<p>Аннотация: Мне очень нравится эта статья. Автор наглядно показывает, как <em>неожиданно</em> иногда хорошие разработчики с прекрасными намерениями пишут плохие тесты:</p>
<p>Слишком часто разработчики ПО подходят к юнит-тестированию, руководствуясь одним и тем же ошибочным мышлением… Они механически применяют все «правила», которые они изучили за время написания продакшн кода, не проверяя, подходят ли они для тестов. В результате «строят небоскребы на пляже».</p>
<p>В статье на конкретных примерах кода показано, как ухудшается читаемость тестов при излишне сложном подходе, и как сохранить простоту. В одной из частей автор демонстрирует, как вдумчивое нарушение принципа DRY позволяет читателю оставаться внутри теста, сохраняя при этом поддерживаемость кода. Эта 11-минутная статья поможет значительно улучшить тесты, написанные разработчиками, которые склонны писать сложно. Если в вашей команде есть такой человек, вы теперь знаете, что делать.</p>
<p>Ссылка на статью: <a href="https://mtlynch.io/good-developers-bad-tests/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">https://mtlynch.io/good-developers-bad-tests/<span class="wpel-icon wpel-image wpel-icon-6"></span></a> </p>
<hr class="wp-block-separator has-alpha-channel-opacity"/>
<h2 class="wp-block-heading"><span class="ez-toc-section" id="8_%C2%AB%D0%9E%D0%B1%D0%B7%D0%BE%D1%80_%D1%82%D0%B5%D1%81%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_JavaScript_%D0%B2_2022_%D0%B3%D0%BE%D0%B4%D1%83%C2%BB"></span>8. «Обзор тестирования JavaScript в 2022 году» <span class="ez-toc-section-end"></span></h2>
<p>Автор: Виталий Зайдман<br>37 мин (7 400 слов), <a href="https://medium.com/welldone-software/an-overview-of-javascript-testing-7ce7298b9870" target="_blank" rel="noopener nofollow external noreferrer" title="статья" data-wpel-link="external" class="wpel-icon-right">статья<span class="wpel-icon wpel-image wpel-icon-6"></span></a></p>
<p>Аннотация: эта статья уникальна тем, что в ней не рассматривается одна тема, а проводится обзор инструментов тестирования JavaScript. Это позволяет существенно обогатить свой инструментарий для любой ситуации. Например, знание о том, что существуют расширения IDE, которые показывают информацию о покрытии прямо в коде, может помочь вам повысить уровень внедрения тестов в команде. Знание о том, что существуют надежные, бесплатные и опенсорсные средства определения визуальной регрессии, может вдохновить вас глубже погрузиться в эту тему, и это лишь несколько примеров.</p>
<p>«Мы рассмотрели наиболее актуальные стратегии и инструменты тестирования в сообществе веб-разработчиков и, надеемся, облегчили вам тестирование сайтов. В конечном счете, наилучшие решения в отношении архитектуры приложений сегодня принимаются путем понимания общих закономерностей, модных в активном сообществе разработчиков, и сочетания их с собственным опытом и особенностями приложений».</p>
<p>В статье рассматриваются такие категории, как библиотеки для проверки утверждений, системы выполнения тестов, средства покрытия кода, средства определения визуальной регрессии, E2E тест-сьюты и многое другое.</p>
<p>Ссылка на статью: <a href="https://medium.com/welldone-software/an-overview-of-javascript-testing-7ce7298b9870" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">https://medium.com/welldone-software/an-overview-of-javascript-testing-7ce7298b9870<span class="wpel-icon wpel-image wpel-icon-6"></span></a></p>
<hr class="wp-block-separator has-alpha-channel-opacity"/>
<h2 class="wp-block-heading"><span class="ez-toc-section" id="9_%C2%AB%D0%91%D0%B5%D0%B7%D0%BE%D0%BF%D0%B0%D1%81%D0%BD%D1%8B%D0%B9_%D1%81%D0%BF%D0%BE%D1%81%D0%BE%D0%B1_%D1%82%D0%B5%D1%81%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_%D0%B2_%D0%BF%D1%80%D0%BE%D0%B4%D0%B0%D0%BA%D1%88%D0%B5%D0%BD%D0%B5%C2%BB"></span>9. «Безопасный способ тестирования в продакшене»<span class="ez-toc-section-end"></span></h2>
<p>Автор: Синди Сридхаран<br>54 мин (10 725 слов), <a href="https://copyconstruct.medium.com/testing-in-production-the-safe-way-18ca102d0ef1" target="_blank" rel="noopener nofollow external noreferrer" title="статья" data-wpel-link="external" class="wpel-icon-right">статья<span class="wpel-icon wpel-image wpel-icon-6"></span></a></p>
<p>Аннотация: «Тестирование в продакшене» — это провокационный термин, который звучит как рискованный и безответственный подход к тестированию и противопоставляется предварительной проверке (еще один случай неудачной терминологии тестирования). На практике тестирование в продакшене не заменяет тестирования во время кодирования, а лишь добавляет <em>дополнительный</em> уровень уверенности за счет <em>безопасного</em> тестирования еще на трех этапах: деплой, релиз и пост-релиз. В этой обширной статье рассматриваются десятки методов. Некоторые из них необычны, например, traffic shadowing (паттерн деплоя, при котором трафик с продакшена асинхронно копируется и подается на сервисы для тестирования), tap compare (техника тестирования, позволяющая проверить поведение и производительность нового сервиса путем сравнения его результатов со старым сервисом) и т.д. Но главное, она иллюстрирует всесторонний процесс тестирования, начиная с компьютера разработчика и заканчивая версией, работающей у пользователей в продакшене.</p>
<p>Я все больше убеждаюсь в том, что промежуточные среды как моки — в лучшем случае это бледная имитация подлинного продукта, а в худшем — предвзятость подтверждения (confirmation bias).</p>
<p>Это все равно лучше, чем ничего — но состояние «работает на промежуточной среде» лишь на один шаг лучше, чем «работает на моей машине».</p>
<figure class="wp-block-image"><img decoding="async" src="https://lh4.googleusercontent.com/uQRYq6t0AlSXdnfyKDFGVIqjQ0Vgi0KscLb_afp2X2zjqJts47GsPwtegdOHaKJnIRYRaBhoWpslwvIhYiwDFVSf-cZmdsr_0JYnNBqn5LaODSXOR5VHQftSFgAP2ujgUSgs18HCAiwS5-JMLeZxo5o" alt="Testing in production"/></figure>
<p>Ссылка на статью: <a href="https://copyconstruct.medium.com/testing-in-production-the-safe-way-18ca102d0ef1" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">https://copyconstruct.medium.com/testing-in-production-the-safe-way-18ca102d0ef1<span class="wpel-icon wpel-image wpel-icon-6"></span></a></p>
<hr class="wp-block-separator has-alpha-channel-opacity"/>
<h2 class="wp-block-heading"><span class="ez-toc-section" id="10_%C2%ABPlease_dont_mock_me%C2%BB_%D0%BF%D1%80%D0%B8%D0%BC%D0%B5%D1%80%D1%8B_%D0%BD%D0%B0_JavaScript_%D1%81_JSConf"></span>10. «Please don’t mock me» (примеры на JavaScript, с JSConf) ***<span class="ez-toc-section-end"></span></h2>
<p>Автор: Джастин Сёрлз<br>39 мин.</p>
<p>Аннотация: Это фантастическое выступление Justin Searls на JSConf US 2018 посвящено ахиллесовой пяте тестирования: где именно писать моки. Дилемма о том, где заканчивается область тестирования, что нужно имитировать, а что нет — это, пожалуй, наиболее стратегические решения в тест-дизайне. Рассмотрим модуль A, который взаимодействует с модулем B. Если изолировать A с помощью имитации B, то A всегда пройдет тест, даже если интерфейс B изменился, а код A не изменился вслед за ним. Это делает тесты A очень стабильными, но… продакшн упадет через несколько часов. В своем выступлении Джастин говорит:</p>
<p>«Тест, который никогда не бывает красным, — это плохой тест, потому что он ни о чем не говорит. Создавайте тесты так, чтобы они могли завершиться ошибкой.</p>
<p>Также он рассуждает о многих других интересных и непростых вопросах, связанных с мокингом, с прекрасными визуальными эффектами и массой идей. Не пропустите это выступление.</p>
<p>Ссылка на видео: <a href="https://www.youtube.com/watch?v=x8sKpJwq6lY&list=PL1CRgzydk3vzk5nMZNLTODfMartQQzInE&index=148" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">https://www.youtube.com/watch?v=x8sKpJwq6lY&list=PL1CRgzydk3vzk5nMZNLTODfMartQQzInE&index=148<span class="wpel-icon wpel-image wpel-icon-6"></span></a></p>
<figure class="wp-block-embed is-type-video is-provider-youtube wp-block-embed-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><div class="wp-block-embed__wrapper">
<iframe title="Please don't mock me - Justin Searls - JSConf US 2018" width="770" height="433" src="https://www.youtube.com/embed/x8sKpJwq6lY?list=PL1CRgzydk3vzk5nMZNLTODfMartQQzInE" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>
</div></figure>
<p>Автор оргинала: Yoni Goldberg<br>Источник: <a href="https://practica.dev/blog/a-compilation-of-outstanding-testing-articles-with-javaScript/" target="_blank" rel="noopener nofollow external noreferrer" title="practica.dev" data-wpel-link="external" class="wpel-icon-right">practica.dev<span class="wpel-icon wpel-image wpel-icon-6"></span></a><br></p>
</div><!-- .post-content -->
<div class="the-post-foot cf">
<div class="tag-share cf">
<div class="post-tags"><a href="https://otus.ru/journal/tag/qa/" rel="tag" data-wpel-link="internal">qa</a><a href="https://otus.ru/journal/tag/podborka/" rel="tag" data-wpel-link="internal">подборка</a><a href="https://otus.ru/journal/tag/testirovanie/" rel="tag" data-wpel-link="internal">тестирование</a></div>
<div class="post-share">
<div class="post-share-icons cf">
<span class="counters">
</span>
<a href="https://www.facebook.com/sharer.php?u=https%3A%2F%2Fotus.ru%2Fjournal%2Ftop-10-statej-po-testirovaniju%2F" class="link facebook wpel-icon-right" target="_blank" title="Share on Facebook" data-wpel-link="external" rel="nofollow external noopener noreferrer"><i class="fa fa-facebook"></i><span class="wpel-icon wpel-image wpel-icon-6"></span></a>
<a href="https://twitter.com/intent/tweet?url=https%3A%2F%2Fotus.ru%2Fjournal%2Ftop-10-statej-po-testirovaniju%2F&text=%D0%9E%D0%B1%D0%B5%D1%81%D0%BF%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D0%B5%20%D0%BA%D0%B0%D1%87%D0%B5%D1%81%D1%82%D0%B2%D0%B0%3A%20%D1%82%D0%BE%D0%BF-10%20%D1%81%D1%82%D0%B0%D1%82%D0%B5%D0%B9" class="link twitter wpel-icon-right" target="_blank" title="Share on Twitter" data-wpel-link="external" rel="nofollow external noopener noreferrer"><i class="fa fa-twitter"></i><span class="wpel-icon wpel-image wpel-icon-6"></span></a>
<a href="https://www.linkedin.com/shareArticle?mini=true&url=https%3A%2F%2Fotus.ru%2Fjournal%2Ftop-10-statej-po-testirovaniju%2F" class="link linkedin wpel-icon-right" target="_blank" title="LinkedIn" data-wpel-link="external" rel="nofollow external noopener noreferrer"><i class="fa fa-linkedin"></i><span class="wpel-icon wpel-image wpel-icon-6"></span></a>
<a href="https://pinterest.com/pin/create/button/?url=https%3A%2F%2Fotus.ru%2Fjournal%2Ftop-10-statej-po-testirovaniju%2F&media=https%3A%2F%2Fotus.ru%2Fjournal%2Fwp-content%2Fuploads%2F2023%2F09%2Foj-1080x720-kopiya-3.png&description=%D0%9E%D0%B1%D0%B5%D1%81%D0%BF%D0%B5%D1%87%D0%B5%D0%BD%D0%B8%D0%B5%20%D0%BA%D0%B0%D1%87%D0%B5%D1%81%D1%82%D0%B2%D0%B0%3A%20%D1%82%D0%BE%D0%BF-10%20%D1%81%D1%82%D0%B0%D1%82%D0%B5%D0%B9" class="link pinterest wpel-icon-right" target="_blank" title="Pinterest" data-wpel-link="external" rel="nofollow external noopener noreferrer"><i class="fa fa-pinterest-p"></i><span class="wpel-icon wpel-image wpel-icon-6"></span></a>
</div>
</div>
</div>
</div>
<div class="post-nav">
<div class="post previous cf">
<a href="https://otus.ru/journal/strong-proekt-po-postroeniju-3-urovnevoj-infrastruktury-dlya-veb-prilozheniya-strong/" title="Prev Post" class="nav-icon" data-wpel-link="internal">
<i class="fa fa-angle-left"></i>
</a>
<span class="content">
<a href="https://otus.ru/journal/strong-proekt-po-postroeniju-3-urovnevoj-infrastruktury-dlya-veb-prilozheniya-strong/" class="image-link" rel="previous" data-wpel-link="internal">
<img width="150" height="106" src="data:image/svg+xml,%3Csvg%20viewBox%3D%270%200%20150%20106%27%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%3E%3C%2Fsvg%3E" class="attachment-thumbnail size-thumbnail lazyload wp-post-image" alt="<strong>Проект по построению 3-уровневой инфраструктуры для веб-приложения</strong>" decoding="async" data-srcset="https://otus.ru/journal/wp-content/uploads/2023/09/oj-1080x720121-1-150x106.jpg 150w, https://otus.ru/journal/wp-content/uploads/2023/09/oj-1080x720121-1-300x212.jpg 300w, https://otus.ru/journal/wp-content/uploads/2023/09/oj-1080x720121-1-1024x724.jpg 1024w, https://otus.ru/journal/wp-content/uploads/2023/09/oj-1080x720121-1-768x543.jpg 768w, https://otus.ru/journal/wp-content/uploads/2023/09/oj-1080x720121-1-1536x1086.jpg 1536w" data-src="https://otus.ru/journal/wp-content/uploads/2023/09/oj-1080x720121-1-150x106.jpg" data-sizes="(max-width: 150px) 100vw, 150px" title="<strong>Проект по построению 3-уровневой инфраструктуры для веб-приложения</strong>" /> </a>
<div class="post-meta">
<span class="label">Prev Post</span>
<div class="post-meta post-meta-b">
<h2 class="post-title">
<a href="https://otus.ru/journal/strong-proekt-po-postroeniju-3-urovnevoj-infrastruktury-dlya-veb-prilozheniya-strong/" data-wpel-link="internal"><strong>Проект по построению 3-уровневой инфраструктуры для веб-приложения</strong></a>
</h2>
<div class="below">
<a href="https://otus.ru/journal/strong-proekt-po-postroeniju-3-urovnevoj-infrastruktury-dlya-veb-prilozheniya-strong/" class="meta-item date-link" data-wpel-link="internal"><time class="post-date" datetime="2023-09-12T21:08:18+00:00">12 сентября, 2023</time></a>
<span class="meta-sep"></span>
<span class="meta-item read-time">5 Mins Read</span>
</div>
</div> </div>
</span>
</div>
<div class="post next cf">
<a href="https://otus.ru/journal/kak-nauchitsya-davat-konstruktivnuju-kritiku-i-ne-trevozhitsya/" title="Next Post" class="nav-icon" data-wpel-link="internal">
<i class="fa fa-angle-right"></i>
</a>
<span class="content">
<a href="https://otus.ru/journal/kak-nauchitsya-davat-konstruktivnuju-kritiku-i-ne-trevozhitsya/" class="image-link" rel="next" data-wpel-link="internal">
<img width="150" height="106" src="data:image/svg+xml,%3Csvg%20viewBox%3D%270%200%20150%20106%27%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%3E%3C%2Fsvg%3E" class="attachment-thumbnail size-thumbnail lazyload wp-post-image" alt="Как научиться давать конструктивную критику и не тревожиться" decoding="async" loading="lazy" data-srcset="https://otus.ru/journal/wp-content/uploads/2023/09/oj-1080x720-kopiya-1-1-150x106.png 150w, https://otus.ru/journal/wp-content/uploads/2023/09/oj-1080x720-kopiya-1-1-300x212.png 300w, https://otus.ru/journal/wp-content/uploads/2023/09/oj-1080x720-kopiya-1-1-1024x724.png 1024w, https://otus.ru/journal/wp-content/uploads/2023/09/oj-1080x720-kopiya-1-1-768x543.png 768w, https://otus.ru/journal/wp-content/uploads/2023/09/oj-1080x720-kopiya-1-1-1536x1086.png 1536w" data-src="https://otus.ru/journal/wp-content/uploads/2023/09/oj-1080x720-kopiya-1-1-150x106.png" data-sizes="(max-width: 150px) 100vw, 150px" title="Как научиться давать конструктивную критику и не тревожиться" /> </a>
<div class="post-meta">
<span class="label">Next Post</span>
<div class="post-meta post-meta-b">
<h2 class="post-title">
<a href="https://otus.ru/journal/kak-nauchitsya-davat-konstruktivnuju-kritiku-i-ne-trevozhitsya/" data-wpel-link="internal">Как научиться давать конструктивную критику и не тревожиться</a>
</h2>
<div class="below">
<a href="https://otus.ru/journal/kak-nauchitsya-davat-konstruktivnuju-kritiku-i-ne-trevozhitsya/" class="meta-item date-link" data-wpel-link="internal"><time class="post-date" datetime="2023-09-14T10:19:03+00:00">14 сентября, 2023</time></a>
<span class="meta-sep"></span>
<span class="meta-item read-time">6 Mins Read</span>
</div>
</div> </div>
</span>
</div>
</div>
<section class="related-posts grid-3">
<h4 class="section-head"><span class="title">Читать ещё</span></h4>
<div class="ts-row posts cf">
<article class="post col-4">
<a href="https://otus.ru/journal/proekt-tg-autoposter-na-nest-js/" title="Проект «TG Autoposter на Nest.JS»" class="image-link" data-wpel-link="internal">
</a>
<div class="content">
<h3 class="post-title"><a href="https://otus.ru/journal/proekt-tg-autoposter-na-nest-js/" class="post-link" data-wpel-link="internal">Проект «TG Autoposter на Nest.JS»</a></h3>
<div class="post-meta">
<time class="post-date" datetime="2025-12-23T00:44:53+00:00">23 декабря, 2025</time>
</div>
</div>
</article >
<article class="post col-4">
<a href="https://otus.ru/journal/langtrainee-razrabotka-mvp-ai-platformy-dlya-personalizirovannogo-izucheniya-yazykov/" title="LangTrainee: разработка MVP AI-платформы для персонализированного изучения языков" class="image-link" data-wpel-link="internal">
</a>
<div class="content">
<h3 class="post-title"><a href="https://otus.ru/journal/langtrainee-razrabotka-mvp-ai-platformy-dlya-personalizirovannogo-izucheniya-yazykov/" class="post-link" data-wpel-link="internal">LangTrainee: разработка MVP AI-платформы для персонализированного изучения языков</a></h3>
<div class="post-meta">
<time class="post-date" datetime="2025-11-12T04:39:47+00:00">12 ноября, 2025</time>
</div>
</div>
</article >
<article class="post col-4">
<a href="https://otus.ru/journal/pochemu-my-ne-uhodim-iz-it-dazhe-kogda-hochetsya/" title="Почему мы не уходим из IT даже когда хочется" class="image-link" data-wpel-link="internal">
<img width="270" height="180" src="data:image/svg+xml,%3Csvg%20viewBox%3D%270%200%20270%20180%27%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%3E%3C%2Fsvg%3E" class="image lazyload wp-post-image" alt="Почему мы не уходим из IT даже когда хочется" title="Почему мы не уходим из IT даже когда хочется" decoding="async" loading="lazy" data-srcset="https://otus.ru/journal/wp-content/uploads/2025/11/oj-1080x720-kopiya-1-270x180.jpg 270w, https://otus.ru/journal/wp-content/uploads/2025/11/oj-1080x720-kopiya-1-770x515.jpg 770w, https://otus.ru/journal/wp-content/uploads/2025/11/oj-1080x720-kopiya-1-370x245.jpg 370w" data-src="https://otus.ru/journal/wp-content/uploads/2025/11/oj-1080x720-kopiya-1-270x180.jpg" data-sizes="(max-width: 270px) 100vw, 270px" /> </a>
<div class="content">
<h3 class="post-title"><a href="https://otus.ru/journal/pochemu-my-ne-uhodim-iz-it-dazhe-kogda-hochetsya/" class="post-link" data-wpel-link="internal">Почему мы не уходим из IT даже когда хочется</a></h3>
<div class="post-meta">
<time class="post-date" datetime="2025-11-04T12:29:53+00:00">4 ноября, 2025</time>
</div>
</div>
</article >
</div>
</section>
</article> <!-- .the-post -->
</div>
<aside class="col-4 sidebar">
<div class="inner">
<ul>
<li id="search-2" class="widget widget_search"><h5 class="widget-title"><span>Поиск по блогу</span></h5>
<form method="get" class="search-form" action="https://otus.ru/journal/">
<label>
<span class="screen-reader-text">Search for:</span>
<input type="search" class="search-field" placeholder="Введите запрос и нажмите Enter" value="" name="s" title="Search for:" />
</label>
<button type="submit" class="search-submit"><i class="fa fa-search"></i></button>
</form>
</li>
<li id="tag_cloud-5" class="widget widget_tag_cloud"><h5 class="widget-title"><span>Метки</span></h5><div class="tagcloud"><a href="https://otus.ru/journal/tag/android-2/" class="tag-cloud-link tag-link-74 tag-link-position-1" style="font-size: 12.472222222222pt;" aria-label="Android (34 элемента)" data-wpel-link="internal">Android</a>
<a href="https://otus.ru/journal/tag/c-3/" class="tag-cloud-link tag-link-91 tag-link-position-2" style="font-size: 10.916666666667pt;" aria-label="C (23 элемента)" data-wpel-link="internal">C</a>
<a href="https://otus.ru/journal/tag/c-2/" class="tag-cloud-link tag-link-81 tag-link-position-3" style="font-size: 12.666666666667pt;" aria-label="C# (35 элементов)" data-wpel-link="internal">C#</a>
<a href="https://otus.ru/journal/tag/c/" class="tag-cloud-link tag-link-20 tag-link-position-4" style="font-size: 12.472222222222pt;" aria-label="c++ (34 элемента)" data-wpel-link="internal">c++</a>
<a href="https://otus.ru/journal/tag/computer-science/" class="tag-cloud-link tag-link-209 tag-link-position-5" style="font-size: 15.972222222222pt;" aria-label="computer science (78 элементов)" data-wpel-link="internal">computer science</a>
<a href="https://otus.ru/journal/tag/css/" class="tag-cloud-link tag-link-288 tag-link-position-6" style="font-size: 8.6805555555556pt;" aria-label="CSS (13 элементов)" data-wpel-link="internal">CSS</a>
<a href="https://otus.ru/journal/tag/data-science/" class="tag-cloud-link tag-link-151 tag-link-position-7" style="font-size: 8pt;" aria-label="Data Science (11 элементов)" data-wpel-link="internal">Data Science</a>
<a href="https://otus.ru/journal/tag/devops/" class="tag-cloud-link tag-link-98 tag-link-position-8" style="font-size: 10.138888888889pt;" aria-label="devops (19 элементов)" data-wpel-link="internal">devops</a>
<a href="https://otus.ru/journal/tag/docker/" class="tag-cloud-link tag-link-143 tag-link-position-9" style="font-size: 8.2916666666667pt;" aria-label="Docker (12 элементов)" data-wpel-link="internal">Docker</a>
<a href="https://otus.ru/journal/tag/gamedev/" class="tag-cloud-link tag-link-25 tag-link-position-10" style="font-size: 11.694444444444pt;" aria-label="gamedev (28 элементов)" data-wpel-link="internal">gamedev</a>
<a href="https://otus.ru/journal/tag/hr/" class="tag-cloud-link tag-link-103 tag-link-position-11" style="font-size: 8pt;" aria-label="hr (11 элементов)" data-wpel-link="internal">hr</a>
<a href="https://otus.ru/journal/tag/html/" class="tag-cloud-link tag-link-217 tag-link-position-12" style="font-size: 11.208333333333pt;" aria-label="HTML (25 элементов)" data-wpel-link="internal">HTML</a>
<a href="https://otus.ru/journal/tag/ios/" class="tag-cloud-link tag-link-101 tag-link-position-13" style="font-size: 8.9722222222222pt;" aria-label="iOS (14 элементов)" data-wpel-link="internal">iOS</a>
<a href="https://otus.ru/journal/tag/it/" class="tag-cloud-link tag-link-50 tag-link-position-14" style="font-size: 10.527777777778pt;" aria-label="IT (21 элемент)" data-wpel-link="internal">IT</a>
<a href="https://otus.ru/journal/tag/java/" class="tag-cloud-link tag-link-75 tag-link-position-15" style="font-size: 15.680555555556pt;" aria-label="Java (73 элемента)" data-wpel-link="internal">Java</a>
<a href="https://otus.ru/journal/tag/javascript/" class="tag-cloud-link tag-link-83 tag-link-position-16" style="font-size: 14.319444444444pt;" aria-label="JavaScript (53 элемента)" data-wpel-link="internal">JavaScript</a>
<a href="https://otus.ru/journal/tag/linux/" class="tag-cloud-link tag-link-141 tag-link-position-17" style="font-size: 11.888888888889pt;" aria-label="Linux (29 элементов)" data-wpel-link="internal">Linux</a>
<a href="https://otus.ru/journal/tag/machine-learning/" class="tag-cloud-link tag-link-167 tag-link-position-18" style="font-size: 8.6805555555556pt;" aria-label="Machine Learning (13 элементов)" data-wpel-link="internal">Machine Learning</a>
<a href="https://otus.ru/journal/tag/otus-book/" class="tag-cloud-link tag-link-261 tag-link-position-19" style="font-size: 9.9444444444444pt;" aria-label="otus book (18 элементов)" data-wpel-link="internal">otus book</a>
<a href="https://otus.ru/journal/tag/php/" class="tag-cloud-link tag-link-45 tag-link-position-20" style="font-size: 10.527777777778pt;" aria-label="PHP (21 элемент)" data-wpel-link="internal">PHP</a>
<a href="https://otus.ru/journal/tag/python/" class="tag-cloud-link tag-link-27 tag-link-position-21" style="font-size: 16.944444444444pt;" aria-label="Python (99 элементов)" data-wpel-link="internal">Python</a>
<a href="https://otus.ru/journal/tag/qa/" class="tag-cloud-link tag-link-155 tag-link-position-22" style="font-size: 11.402777777778pt;" aria-label="qa (26 элементов)" data-wpel-link="internal">qa</a>
<a href="https://otus.ru/journal/tag/sql/" class="tag-cloud-link tag-link-38 tag-link-position-23" style="font-size: 12.861111111111pt;" aria-label="SQL (37 элементов)" data-wpel-link="internal">SQL</a>
<a href="https://otus.ru/journal/tag/team-lead/" class="tag-cloud-link tag-link-364 tag-link-position-24" style="font-size: 9.9444444444444pt;" aria-label="team lead (18 элементов)" data-wpel-link="internal">team lead</a>
<a href="https://otus.ru/journal/tag/unity/" class="tag-cloud-link tag-link-24 tag-link-position-25" style="font-size: 8pt;" aria-label="unity (11 элементов)" data-wpel-link="internal">unity</a>
<a href="https://otus.ru/journal/tag/algoritmy/" class="tag-cloud-link tag-link-30 tag-link-position-26" style="font-size: 9.9444444444444pt;" aria-label="Алгоритмы (18 элементов)" data-wpel-link="internal">Алгоритмы</a>
<a href="https://otus.ru/journal/tag/bazy-dannyh/" class="tag-cloud-link tag-link-40 tag-link-position-27" style="font-size: 10.138888888889pt;" aria-label="Базы данных (19 элементов)" data-wpel-link="internal">Базы данных</a>
<a href="https://otus.ru/journal/tag/matematika/" class="tag-cloud-link tag-link-44 tag-link-position-28" style="font-size: 10.916666666667pt;" aria-label="Математика (23 элемента)" data-wpel-link="internal">Математика</a>
<a href="https://otus.ru/journal/tag/arhitektura-po/" class="tag-cloud-link tag-link-10 tag-link-position-29" style="font-size: 9.4583333333333pt;" aria-label="архитектура ПО (16 элементов)" data-wpel-link="internal">архитектура ПО</a>
<a href="https://otus.ru/journal/tag/bazy-dannyh-2/" class="tag-cloud-link tag-link-251 tag-link-position-30" style="font-size: 10.138888888889pt;" aria-label="базы данных (19 элементов)" data-wpel-link="internal">базы данных</a>
<a href="https://otus.ru/journal/tag/vebinar/" class="tag-cloud-link tag-link-201 tag-link-position-31" style="font-size: 13.930555555556pt;" aria-label="вебинар (48 элементов)" data-wpel-link="internal">вебинар</a>
<a href="https://otus.ru/journal/tag/dajdzhest/" class="tag-cloud-link tag-link-308 tag-link-position-32" style="font-size: 10.722222222222pt;" aria-label="дайджест (22 элемента)" data-wpel-link="internal">дайджест</a>
<a href="https://otus.ru/journal/tag/zapis-vebinara/" class="tag-cloud-link tag-link-226 tag-link-position-33" style="font-size: 14.902777777778pt;" aria-label="запись вебинара (61 элемент)" data-wpel-link="internal">запись вебинара</a>
<a href="https://otus.ru/journal/tag/zapis-uroka/" class="tag-cloud-link tag-link-272 tag-link-position-34" style="font-size: 16.069444444444pt;" aria-label="запись урока (80 элементов)" data-wpel-link="internal">запись урока</a>
<a href="https://otus.ru/journal/tag/informacionnaya-bezopasnost/" class="tag-cloud-link tag-link-232 tag-link-position-35" style="font-size: 10.138888888889pt;" aria-label="информационная безопасность (19 элементов)" data-wpel-link="internal">информационная безопасность</a>
<a href="https://otus.ru/journal/tag/karera-v-it/" class="tag-cloud-link tag-link-292 tag-link-position-36" style="font-size: 9.9444444444444pt;" aria-label="карьера в IT (18 элементов)" data-wpel-link="internal">карьера в IT</a>
<a href="https://otus.ru/journal/tag/podborka/" class="tag-cloud-link tag-link-7 tag-link-position-37" style="font-size: 12.666666666667pt;" aria-label="подборка (35 элементов)" data-wpel-link="internal">подборка</a>
<a href="https://otus.ru/journal/tag/podborka-statej/" class="tag-cloud-link tag-link-219 tag-link-position-38" style="font-size: 15.777777777778pt;" aria-label="подборка статей (75 элементов)" data-wpel-link="internal">подборка статей</a>
<a href="https://otus.ru/journal/tag/programmirovanie/" class="tag-cloud-link tag-link-65 tag-link-position-39" style="font-size: 22pt;" aria-label="программирование (332 элемента)" data-wpel-link="internal">программирование</a>
<a href="https://otus.ru/journal/tag/proekt/" class="tag-cloud-link tag-link-321 tag-link-position-40" style="font-size: 11.888888888889pt;" aria-label="проект (29 элементов)" data-wpel-link="internal">проект</a>
<a href="https://otus.ru/journal/tag/proektnaya-rabota/" class="tag-cloud-link tag-link-310 tag-link-position-41" style="font-size: 11.597222222222pt;" aria-label="проектная работа (27 элементов)" data-wpel-link="internal">проектная работа</a>
<a href="https://otus.ru/journal/tag/seti/" class="tag-cloud-link tag-link-181 tag-link-position-42" style="font-size: 12.958333333333pt;" aria-label="сети (38 элементов)" data-wpel-link="internal">сети</a>
<a href="https://otus.ru/journal/tag/testirovanie/" class="tag-cloud-link tag-link-69 tag-link-position-43" style="font-size: 13.930555555556pt;" aria-label="тестирование (48 элементов)" data-wpel-link="internal">тестирование</a>
<a href="https://otus.ru/journal/tag/upravlenie-komandoj/" class="tag-cloud-link tag-link-63 tag-link-position-44" style="font-size: 11.694444444444pt;" aria-label="управление командой (28 элементов)" data-wpel-link="internal">управление командой</a>
<a href="https://otus.ru/journal/tag/habr-2/" class="tag-cloud-link tag-link-203 tag-link-position-45" style="font-size: 13.930555555556pt;" aria-label="хабр (48 элементов)" data-wpel-link="internal">хабр</a></div>
</li>
</ul>
</div>
</aside>
</div> <!-- .ts-row -->
</div> <!-- .main -->
<footer class="main-footer dark bold">
<section class="lower-footer cf">
<div class="wrap">
<div class="links">
<div class="menu-menju-navykov-container"><ul id="menu-menju-navykov-1" class="menu"><li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10413"><a href="https://otus.ru/categories/programming/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Программирование<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10414"><a href="https://otus.ru/categories/architecture/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Архитектура<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10415"><a href="https://otus.ru/categories/operations/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Инфраструктура<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10416"><a href="https://otus.ru/categories/information-security-courses/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Безопасность<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10417"><a href="https://otus.ru/categories/data-science/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Data Science<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10418"><a href="https://otus.ru/categories/gamedev/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">GameDev<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10419"><a href="https://otus.ru/categories/marketing-business/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Управление<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10420"><a href="https://otus.ru/categories/analytics/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Аналитика и анализ<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
<li class="menu-item menu-item-type-custom menu-item-object-custom menu-item-10421"><a href="https://otus.ru/categories/testing/" data-wpel-link="external" target="_blank" rel="nofollow external noopener noreferrer" class="wpel-icon-right">Тестирование<span class="wpel-icon wpel-image wpel-icon-6"></span></a></li>
</ul></div> </div>
<p class="copyright"> © 2015-2026 OTUS </p>
<div class="to-top">
<a href="#" class="back-to-top"><i class="fa fa-angle-up"></i> Top</a>
</div>
</div>
</section>
</footer>
</div> <!-- .main-wrap -->
<div class="mobile-menu-container off-canvas" id="mobile-menu">
<a href="#" class="close"><i class="fa fa-times"></i></a>
<div class="logo">
</div>
<ul class="mobile-menu"></ul>
</div>
<div class="search-modal-wrap">
<div class="search-modal-box" role="dialog" aria-modal="true">
<form method="get" class="search-form" action="https://otus.ru/journal/">
<input type="search" class="search-field" name="s" placeholder="Search..." value="" required />
<button type="submit" class="search-submit visuallyhidden">Submit</button>
<p class="message">
Type above and press <em>Enter</em> to search. Press <em>Esc</em> to cancel. </p>
</form>
</div>
</div>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/plugins/clearfy/components/comments-plus/assets/js/url-span.js" id="wbcr-comments-plus-url-span-js"></script>
<script type="text/javascript" id="ez-toc-scroll-scriptjs-js-extra">
/* <![CDATA[ */
var eztoc_smooth_local = {"scroll_offset":"30"};
/* ]]> */
</script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/plugins/easy-table-of-contents/assets/js/smooth_scroll.min.js" id="ez-toc-scroll-scriptjs-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/plugins/easy-table-of-contents/vendor/js-cookie/js.cookie.min.js" id="ez-toc-js-cookie-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/plugins/easy-table-of-contents/vendor/sticky-kit/jquery.sticky-kit.min.js" id="ez-toc-jquery-sticky-kit-js"></script>
<script type="text/javascript" id="ez-toc-js-js-extra">
/* <![CDATA[ */
var ezTOC = {"smooth_scroll":"1","visibility_hide_by_default":"","scroll_offset":"30","fallbackIcon":"<span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #999;color:#999\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #999;color:#999\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span>"};
/* ]]> */
</script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/plugins/easy-table-of-contents/assets/js/front.min.js" id="ez-toc-js-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/themes/contentberg/js/custom-script.js" id="custom-script-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/themes/contentberg/js/magnific-popup.js" id="magnific-popup-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/themes/contentberg/js/jquery.fitvids.js" id="jquery-fitvids-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-includes/js/imagesloaded.min.js" id="imagesloaded-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/themes/contentberg/js/object-fit-images.js" id="object-fit-images-js"></script>
<script type="text/javascript" id="contentberg-theme-js-extra">
/* <![CDATA[ */
var Bunyad = {"custom_ajax_url":"\/journal\/top-10-statej-po-testirovaniju\/"};
/* ]]> */
</script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/themes/contentberg/js/theme.js" id="contentberg-theme-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/themes/contentberg/js/theia-sticky-sidebar.js" id="theia-sticky-sidebar-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/themes/contentberg/js/jquery.slick.js" id="jquery-slick-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-content/themes/contentberg/js/jarallax.js" id="jarallax-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-includes/js/masonry.min.js" id="masonry-js"></script>
<script type="text/javascript" src="https://otus.ru/journal/wp-includes/js/jquery/jquery.masonry.min.js" id="jquery-masonry-js"></script>
</body>
</html>
<!-- Cache served by breeze CACHE - Last modified: Tue, 10 Mar 2026 14:49:00 GMT -->