0 added
0 removed
Original
2026-01-01
Modified
2026-02-21
1
<p><a>#статьи</a></p>
1
<p><a>#статьи</a></p>
2
<ul><li>11 сен 2023</li>
2
<ul><li>11 сен 2023</li>
3
<li>0</li>
3
<li>0</li>
4
</ul><p>Изучаем главный инструмент тестировщика приложений на Java и пишем первую программу по методологии TDD.</p>
4
</ul><p>Изучаем главный инструмент тестировщика приложений на Java и пишем первую программу по методологии TDD.</p>
5
<p>Иллюстрация: Оля Ежак для Skillbox Media</p>
5
<p>Иллюстрация: Оля Ежак для Skillbox Media</p>
6
<p>Пишет о сетях, инструментах для разработчиков и языках программирования. Любит готовить, играть в инди‑игры и программировать на Python.</p>
6
<p>Пишет о сетях, инструментах для разработчиков и языках программирования. Любит готовить, играть в инди‑игры и программировать на Python.</p>
7
<p>Пока приложение или сайт небольшие, для контроля качества достаточно мануальных тестировщиков, проверяющих работу "руками". Но что делать, когда в приложении уже сотни файлов и десятки тысяч строк кода? Тестировать вручную становится долго и дорого.</p>
7
<p>Пока приложение или сайт небольшие, для контроля качества достаточно мануальных тестировщиков, проверяющих работу "руками". Но что делать, когда в приложении уже сотни файлов и десятки тысяч строк кода? Тестировать вручную становится долго и дорого.</p>
8
<p>Для таких случаев используют специальные тестовые фреймворки. Один из них - JUnit, фреймворк для модульного тестирования Java-приложений. Он позволяет проводить автоматизированные юнит- и интеграционные тесты.</p>
8
<p>Для таких случаев используют специальные тестовые фреймворки. Один из них - JUnit, фреймворк для модульного тестирования Java-приложений. Он позволяет проводить автоматизированные юнит- и интеграционные тесты.</p>
9
<p>Из этой статьи вы узнаете:</p>
9
<p>Из этой статьи вы узнаете:</p>
10
<ul><li><a>что такое JUnit</a>;</li>
10
<ul><li><a>что такое JUnit</a>;</li>
11
<li><a>какие аннотации в нём используются</a>;</li>
11
<li><a>какие аннотации в нём используются</a>;</li>
12
<li><a>в чём разница между JUnit4 и JUnit5</a>;</li>
12
<li><a>в чём разница между JUnit4 и JUnit5</a>;</li>
13
<li><a>как установить JUnit</a>;</li>
13
<li><a>как установить JUnit</a>;</li>
14
<li><a>как он работает</a>;</li>
14
<li><a>как он работает</a>;</li>
15
<li><a>что такое test-driven development</a>;</li>
15
<li><a>что такое test-driven development</a>;</li>
16
<li><a>как написать приложение по принципам TDD</a>.</li>
16
<li><a>как написать приложение по принципам TDD</a>.</li>
17
</ul><p>JUnit - фреймворк для автоматического юнит-тестирования приложений. Он содержит специальные функции и правила, которые позволяют легко писать и запускать тесты, то есть проверять, что каждый блок кода, или модуль, ответственный за определённую функцию программы, работает как надо. Такой вид тестирования называют модульным, или юнит-тестированием.</p>
17
</ul><p>JUnit - фреймворк для автоматического юнит-тестирования приложений. Он содержит специальные функции и правила, которые позволяют легко писать и запускать тесты, то есть проверять, что каждый блок кода, или модуль, ответственный за определённую функцию программы, работает как надо. Такой вид тестирования называют модульным, или юнит-тестированием.</p>
18
<p>Последняя версия фреймворка -<a>JUnit 5</a>. Она состоит из трёх модулей: JUnit Platform, JUnit Jupiter и JUnit Vintage.</p>
18
<p>Последняя версия фреймворка -<a>JUnit 5</a>. Она состоит из трёх модулей: JUnit Platform, JUnit Jupiter и JUnit Vintage.</p>
19
<p><strong>JUnit Platform</strong> - основной модуль для управления тестами.</p>
19
<p><strong>JUnit Platform</strong> - основной модуль для управления тестами.</p>
20
<p><strong>JUnit Jupiter</strong> - модуль, который использует новые возможности Java 8. Он предоставляет API на основе аннотаций и позволяет работать с модульными и динамическими тестами.</p>
20
<p><strong>JUnit Jupiter</strong> - модуль, который использует новые возможности Java 8. Он предоставляет API на основе аннотаций и позволяет работать с модульными и динамическими тестами.</p>
21
<p><strong>JUnit Vintage</strong> - модуль для поддержки тестов, написанных с использованием JUnit 3 и JUnit 4.</p>
21
<p><strong>JUnit Vintage</strong> - модуль для поддержки тестов, написанных с использованием JUnit 3 и JUnit 4.</p>
22
<p>JUnit удобен тем, что разработчик может гибко указывать условия тестирования. Например, объединять тесты в группы, распределяя их по функциональности, тестируемым модулям или уровню критичности, прописывать условия запуска для каждого блока кода и анализировать результаты по отдельности. Всё это облегчает работу программиста или QA-инженера.</p>
22
<p>JUnit удобен тем, что разработчик может гибко указывать условия тестирования. Например, объединять тесты в группы, распределяя их по функциональности, тестируемым модулям или уровню критичности, прописывать условия запуска для каждого блока кода и анализировать результаты по отдельности. Всё это облегчает работу программиста или QA-инженера.</p>
23
<p>Аннотации в JUnit - это специальные метки, которые Java-разработчик размещает перед методами в тестовом классе. Они позволяют настраивать процесс тестирования, указывая фреймворку, как именно их следует обрабатывать. Например, можно явно указать, какие из методов являются тестовыми случаями, какие из них выполнять перед тестами и после и так далее.</p>
23
<p>Аннотации в JUnit - это специальные метки, которые Java-разработчик размещает перед методами в тестовом классе. Они позволяют настраивать процесс тестирования, указывая фреймворку, как именно их следует обрабатывать. Например, можно явно указать, какие из методов являются тестовыми случаями, какие из них выполнять перед тестами и после и так далее.</p>
24
<p>Вот несколько базовых аннотаций.</p>
24
<p>Вот несколько базовых аннотаций.</p>
25
<p>@Test. Эту аннотацию ставим перед методами, которые относятся к тестовым случаям. JUnit поймёт, что их следует выполнять в качестве теста, а по завершении проверить результат.</p>
25
<p>@Test. Эту аннотацию ставим перед методами, которые относятся к тестовым случаям. JUnit поймёт, что их следует выполнять в качестве теста, а по завершении проверить результат.</p>
26
<p>@Before. Используется для методов, которые должны быть выполнены перед каждым тестовым случаем. Например, если у нас есть несколько тестов, которые требуют одних и тех же начальных условий, мы можем обозначить метод с аннотацией @Before, задав необходимые условия тестирования один раз.</p>
26
<p>@Before. Используется для методов, которые должны быть выполнены перед каждым тестовым случаем. Например, если у нас есть несколько тестов, которые требуют одних и тех же начальных условий, мы можем обозначить метод с аннотацией @Before, задав необходимые условия тестирования один раз.</p>
27
<p>@After. Эту аннотацию используем перед методом, который должен быть выполнен после тестового случая.</p>
27
<p>@After. Эту аннотацию используем перед методом, который должен быть выполнен после тестового случая.</p>
28
<p>@BeforeClass, @AfterClass. Методы с аннотацией @BeforeClass выполняются перед запуском первого теста в классе, а методы с аннотацией @AfterClass - после завершения всех тестов в классе.</p>
28
<p>@BeforeClass, @AfterClass. Методы с аннотацией @BeforeClass выполняются перед запуском первого теста в классе, а методы с аннотацией @AfterClass - после завершения всех тестов в классе.</p>
29
<p>@Ignore. Используется перед методом, чтобы отключить его выполнение в тесте. Это может быть полезно, если мы не уверены в работоспособности отдельных тестов и не хотим их использовать, но должны оставить в коде.</p>
29
<p>@Ignore. Используется перед методом, чтобы отключить его выполнение в тесте. Это может быть полезно, если мы не уверены в работоспособности отдельных тестов и не хотим их использовать, но должны оставить в коде.</p>
30
<p>@BeforeEach и @AfterEach. Аналоги @Before и @After в JUnit 4.</p>
30
<p>@BeforeEach и @AfterEach. Аналоги @Before и @After в JUnit 4.</p>
31
<p>Полный список аннотаций с подробными объяснениями и примерами использования можно прочесть в <a>документации</a>.</p>
31
<p>Полный список аннотаций с подробными объяснениями и примерами использования можно прочесть в <a>документации</a>.</p>
32
<p>Вот как аннотации выглядят в коде:</p>
32
<p>Вот как аннотации выглядят в коде:</p>
33
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.AfterEach; public class MyTest { @BeforeEach public void setUp() { // Метод, выполняющийся перед каждым тестовым случаем } @AfterEach public void tearDown() { // Метод, выполняющийся после каждого тестового случая } @Test public void testSomething() { // Тестовый случай } @Test public void testAnotherThing() { // Другой тестовый случай } }<p>JUnit 4 и JUnit 5 - это две последние версии фреймворка JUnit, которые сейчас распространены в разработке. Между собой они различаются функциональностью, синтаксисом и возможностями.</p>
33
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.AfterEach; public class MyTest { @BeforeEach public void setUp() { // Метод, выполняющийся перед каждым тестовым случаем } @AfterEach public void tearDown() { // Метод, выполняющийся после каждого тестового случая } @Test public void testSomething() { // Тестовый случай } @Test public void testAnotherThing() { // Другой тестовый случай } }<p>JUnit 4 и JUnit 5 - это две последние версии фреймворка JUnit, которые сейчас распространены в разработке. Между собой они различаются функциональностью, синтаксисом и возможностями.</p>
34
<p>Тестовые методы в JUnit 4 помечаются аннотацией @Test. Для определения методов, выполняющихся до и после тестового случая, используют аннотации @Before и @After.</p>
34
<p>Тестовые методы в JUnit 4 помечаются аннотацией @Test. Для определения методов, выполняющихся до и после тестового случая, используют аннотации @Before и @After.</p>
35
<p>В этой версии фреймворка поддерживаются параметризованные тесты с использованием аннотации @RunWith(Parameterized.class). Это значит, что в тест можно передать параметры, необходимые для тестирования.</p>
35
<p>В этой версии фреймворка поддерживаются параметризованные тесты с использованием аннотации @RunWith(Parameterized.class). Это значит, что в тест можно передать параметры, необходимые для тестирования.</p>
36
<p>Тесты, написанные на JUnit 4, могут выполняться в JUnit 5 с использованием JUnit Vintage.</p>
36
<p>Тесты, написанные на JUnit 4, могут выполняться в JUnit 5 с использованием JUnit Vintage.</p>
37
<p>В пятой версии фреймворка появились новые модули:<a>Jupiter</a> - для тестирования с использованием возможностей Java 8, и <a>Platform</a> - модуль для запуска тестов.</p>
37
<p>В пятой версии фреймворка появились новые модули:<a>Jupiter</a> - для тестирования с использованием возможностей Java 8, и <a>Platform</a> - модуль для запуска тестов.</p>
38
<p>Также в JUnit 5 появилась возможность писать собственные расширения для тестов и запускать их по аннотации @ExtendWith. По аналогии с JUnit 4 поддерживаются параметризованные тесты с аннотацией @ParameterizedTest.</p>
38
<p>Также в JUnit 5 появилась возможность писать собственные расширения для тестов и запускать их по аннотации @ExtendWith. По аналогии с JUnit 4 поддерживаются параметризованные тесты с аннотацией @ParameterizedTest.</p>
39
<p>В примерах с кодом мы будем использовать JUnit 5 - это современная версия фреймворка, которая поддерживает Java 8 и JUnit 4.</p>
39
<p>В примерах с кодом мы будем использовать JUnit 5 - это современная версия фреймворка, которая поддерживает Java 8 и JUnit 4.</p>
40
<p>Всё просто - добавляем необходимую зависимость в конфигурационный файл сборщика.</p>
40
<p>Всё просто - добавляем необходимую зависимость в конфигурационный файл сборщика.</p>
41
<p><strong>Для</strong><a><strong>Maven</strong></a><strong>:</strong></p>
41
<p><strong>Для</strong><a><strong>Maven</strong></a><strong>:</strong></p>
42
<ul><li>Зайдите в файл pom.xml.</li>
42
<ul><li>Зайдите в файл pom.xml.</li>
43
<li>Найдите секцию <dependencies>.</li>
43
<li>Найдите секцию <dependencies>.</li>
44
<li>Добавьте внутрь блок:</li>
44
<li>Добавьте внутрь блок:</li>
45
</ul><dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>5.8.2</version> <!-- Версия может быть другой, актуальную версию смотрите на сайте JUnit --> <scope>test</scope> </dependency><ul><li>Сохраните изменения.</li>
45
</ul><dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>5.8.2</version> <!-- Версия может быть другой, актуальную версию смотрите на сайте JUnit --> <scope>test</scope> </dependency><ul><li>Сохраните изменения.</li>
46
</ul><p><strong>Для Gradle:</strong></p>
46
</ul><p><strong>Для Gradle:</strong></p>
47
<ul><li>Зайдите в build.gradle.</li>
47
<ul><li>Зайдите в build.gradle.</li>
48
<li>Найдите секцию dependencies.</li>
48
<li>Найдите секцию dependencies.</li>
49
<li>Добавьте внутрь блок с кодом:</li>
49
<li>Добавьте внутрь блок с кодом:</li>
50
</ul>testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2'<p>Важно, что при работе с Gradle необходимо указать версию фреймворка. Мы рекомендуем использовать наиболее актуальную. Посмотреть её можно на <a>главной странице сайта</a>под заголовком Latest Release.</p>
50
</ul>testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2'<p>Важно, что при работе с Gradle необходимо указать версию фреймворка. Мы рекомендуем использовать наиболее актуальную. Посмотреть её можно на <a>главной странице сайта</a>под заголовком Latest Release.</p>
51
<ul><li>Сохраните изменения.</li>
51
<ul><li>Сохраните изменения.</li>
52
</ul><p>Напишем на Java простой калькулятор:</p>
52
</ul><p>Напишем на Java простой калькулятор:</p>
53
public class Calculator { public int add(int a, int b) { return a + b; } public int subtract(int a, int b) { return a - b; } public int multiply(int a, int b) { return a * b; } public int divide(int a, int b) { if (b == 0) { throw new IllegalArgumentException("Cannot divide by zero"); } return a / b; } }<p>Для модульного тестирования калькулятора нам требуется написать отдельные тесты для сложения, вычитания, умножения и два теста для деления. С JUnit код будет такой:</p>
53
public class Calculator { public int add(int a, int b) { return a + b; } public int subtract(int a, int b) { return a - b; } public int multiply(int a, int b) { return a * b; } public int divide(int a, int b) { if (b == 0) { throw new IllegalArgumentException("Cannot divide by zero"); } return a / b; } }<p>Для модульного тестирования калькулятора нам требуется написать отдельные тесты для сложения, вычитания, умножения и два теста для деления. С JUnit код будет такой:</p>
54
import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; public class CalculatorTest { @Test public void testAddition() { Calculator calculator = new Calculator(); int result = calculator.add(3, 5); assertEquals(8, result); } @Test public void testSubtraction() { Calculator calculator = new Calculator(); int result = calculator.subtract(10, 4); assertEquals(6, result); } @Test public void testMultiplication() { Calculator calculator = new Calculator(); int result = calculator.multiply(6, 3); assertEquals(18, result); } @Test public void testDivision() { Calculator calculator = new Calculator(); int result = calculator.divide(10, 2); assertEquals(5, result); } @Test public void testDivisionByZero() { Calculator calculator = new Calculator(); assertThrows(IllegalArgumentException.class, () -> { calculator.divide(10, 0); }); } }<p>Разберем его:</p>
54
import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; public class CalculatorTest { @Test public void testAddition() { Calculator calculator = new Calculator(); int result = calculator.add(3, 5); assertEquals(8, result); } @Test public void testSubtraction() { Calculator calculator = new Calculator(); int result = calculator.subtract(10, 4); assertEquals(6, result); } @Test public void testMultiplication() { Calculator calculator = new Calculator(); int result = calculator.multiply(6, 3); assertEquals(18, result); } @Test public void testDivision() { Calculator calculator = new Calculator(); int result = calculator.divide(10, 2); assertEquals(5, result); } @Test public void testDivisionByZero() { Calculator calculator = new Calculator(); assertThrows(IllegalArgumentException.class, () -> { calculator.divide(10, 0); }); } }<p>Разберем его:</p>
55
<p><strong>import org.junit.jupiter.api.Test;</strong> - здесь мы импортировали аннотацию Test из фреймворка JUnit. Она помечает методы как тестовые случаи, определяя их выполнение во время запуска тестов.</p>
55
<p><strong>import org.junit.jupiter.api.Test;</strong> - здесь мы импортировали аннотацию Test из фреймворка JUnit. Она помечает методы как тестовые случаи, определяя их выполнение во время запуска тестов.</p>
56
<p><strong>import static org.junit.jupiter.api.Assertions.*;</strong> - импортировали статические методы утверждений (assertions) из класса Assert - assertEquals(expected, actual). Они сравнивают ожидаемые и фактические результаты тестов. Если результаты не совпадают, то тест считается не пройденным.</p>
56
<p><strong>import static org.junit.jupiter.api.Assertions.*;</strong> - импортировали статические методы утверждений (assertions) из класса Assert - assertEquals(expected, actual). Они сравнивают ожидаемые и фактические результаты тестов. Если результаты не совпадают, то тест считается не пройденным.</p>
57
<p><strong>public class CalculatorTest {… }</strong> - определили класс для наших тестов.</p>
57
<p><strong>public class CalculatorTest {… }</strong> - определили класс для наших тестов.</p>
58
<p>Далее мы прописали тестовые методы, например testAddition(), testSubtraction(), testMultiplication(), public void testDivision(). Внутри каждого метода тестируем конкретную арифметическую операцию. Для этого мы сравниваем результат работы калькулятора с заранее подобранным правильным ответом с помощью assertEquals.</p>
58
<p>Далее мы прописали тестовые методы, например testAddition(), testSubtraction(), testMultiplication(), public void testDivision(). Внутри каждого метода тестируем конкретную арифметическую операцию. Для этого мы сравниваем результат работы калькулятора с заранее подобранным правильным ответом с помощью assertEquals.</p>
59
<p>Для каждого теста создали экземпляр класса Calculator, который будет использоваться для их проведения.</p>
59
<p>Для каждого теста создали экземпляр класса Calculator, который будет использоваться для их проведения.</p>
60
<p>В этом примере мы сначала написали программу, а потом - тесты для неё. Но иногда разработчики используют другой подход.</p>
60
<p>В этом примере мы сначала написали программу, а потом - тесты для неё. Но иногда разработчики используют другой подход.</p>
61
<p>Test-driven development (TDD) - это подход к разработке программ, при котором разработчик сначала описывает тесты для функции, которую хочет создать, а затем пишет сам код, который проходит эти тесты.</p>
61
<p>Test-driven development (TDD) - это подход к разработке программ, при котором разработчик сначала описывает тесты для функции, которую хочет создать, а затем пишет сам код, который проходит эти тесты.</p>
62
<p>При таком подходе главные издержки разработки - время на рефакторинг и исправление ошибок - снижаются. А значит, уменьшаются и затраты на создание и поддержку продукта.</p>
62
<p>При таком подходе главные издержки разработки - время на рефакторинг и исправление ошибок - снижаются. А значит, уменьшаются и затраты на создание и поддержку продукта.</p>
63
<p>Упрощённо TDD можно представить в виде нескольких шагов:</p>
63
<p>Упрощённо TDD можно представить в виде нескольких шагов:</p>
64
<ul><li><strong>Написание теста.</strong>Разработчик начинает работу с создания теста, который будет проверять работоспособность кода.</li>
64
<ul><li><strong>Написание теста.</strong>Разработчик начинает работу с создания теста, который будет проверять работоспособность кода.</li>
65
<li><strong>Запуск теста.</strong>При первом запуске тест не должен быть пройден, так как функционального кода программы ещё нет.</li>
65
<li><strong>Запуск теста.</strong>При первом запуске тест не должен быть пройден, так как функционального кода программы ещё нет.</li>
66
<li><strong>Написание кода.</strong>Разработчик пишет код с минимальной функциональностью, которая позволяет успешно пройти тест.</li>
66
<li><strong>Написание кода.</strong>Разработчик пишет код с минимальной функциональностью, которая позволяет успешно пройти тест.</li>
67
<li><strong>Повторный запуск теста.</strong>При повторном запуске тест должен быть пройден удачно.</li>
67
<li><strong>Повторный запуск теста.</strong>При повторном запуске тест должен быть пройден удачно.</li>
68
<li><strong>Рефакторинг.</strong>После успешного завершения тестов разработчик может приступить к рефакторингу - улучшению и оптимизации кода. Важно, что после каждого изменения запуск теста повторяется.</li>
68
<li><strong>Рефакторинг.</strong>После успешного завершения тестов разработчик может приступить к рефакторингу - улучшению и оптимизации кода. Важно, что после каждого изменения запуск теста повторяется.</li>
69
</ul><p>Каждый функциональный модуль, который добавляется в приложение, должен пройти эти этапы. Таким образом, разработчик уже в процессе написания отдельных частей программы подтверждает, что они успешно проходят тесты.</p>
69
</ul><p>Каждый функциональный модуль, который добавляется в приложение, должен пройти эти этапы. Таким образом, разработчик уже в процессе написания отдельных частей программы подтверждает, что они успешно проходят тесты.</p>
70
<p>Используя подход TDD, создадим простое приложение - программу для вычисления факториала числа. Сначала напишем тесты, а затем функциональный код.</p>
70
<p>Используя подход TDD, создадим простое приложение - программу для вычисления факториала числа. Сначала напишем тесты, а затем функциональный код.</p>
71
<p>Работать будем в среде разработки IntelliJ IDEA с Maven на борту. Как создать и инициализировать проект в Maven и подключить JUnit,<a>смотрите выше</a>. А мы перейдём к коду.</p>
71
<p>Работать будем в среде разработки IntelliJ IDEA с Maven на борту. Как создать и инициализировать проект в Maven и подключить JUnit,<a>смотрите выше</a>. А мы перейдём к коду.</p>
72
<p>Создайте файл для тестов в папке test\java. У нас он будет называться NumberUtilTest.java.</p>
72
<p>Создайте файл для тестов в папке test\java. У нас он будет называться NumberUtilTest.java.</p>
73
<em>Скриншот: Skillbox Media</em><p>Напишите тест для функции вычисления факториала, по аналогии с тестированием калькулятора:</p>
73
<em>Скриншот: Skillbox Media</em><p>Напишите тест для функции вычисления факториала, по аналогии с тестированием калькулятора:</p>
74
import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; public class NumberUtilTest { @Test public void testFactorial() { NumberUtil util = new NumberUtil(); int result = util.factorial(5); // Определяем факториал числа 5 assertEquals(120, result); // Сравниваем результат с правильным ответом } }<p>Основываясь на тесте, пропишите в папке main/java класс с названием NumberUtil. Класс пока что оставьте пустым:</p>
74
import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; public class NumberUtilTest { @Test public void testFactorial() { NumberUtil util = new NumberUtil(); int result = util.factorial(5); // Определяем факториал числа 5 assertEquals(120, result); // Сравниваем результат с правильным ответом } }<p>Основываясь на тесте, пропишите в папке main/java класс с названием NumberUtil. Класс пока что оставьте пустым:</p>
75
<em>Скриншот: Skillbox Media</em><p>Запустим наш тест:</p>
75
<em>Скриншот: Skillbox Media</em><p>Запустим наш тест:</p>
76
<em>Скриншот: Skillbox Media</em><p>Тест не пройден. Пока так и должно быть - наш класс ничего не содержит:</p>
76
<em>Скриншот: Skillbox Media</em><p>Тест не пройден. Пока так и должно быть - наш класс ничего не содержит:</p>
77
<em>Скриншот: Skillbox Media</em><p>Теперь реализуйте функцию factorial в классе NumberUtil, чтобы тест прошёл успешно:</p>
77
<em>Скриншот: Skillbox Media</em><p>Теперь реализуйте функцию factorial в классе NumberUtil, чтобы тест прошёл успешно:</p>
78
public class NumberUtil { public int factorial(int n) { if (n < 0) { throw new IllegalArgumentException("Факториал не может быть рассчитан для отрицательных чисел"); } if (n == 0 || n == 1) { return 1; } return n * factorial(n - 1); } }<p>Запустите тест снова. Если вы всё сделали правильно, то он пройдёт успешно:</p>
78
public class NumberUtil { public int factorial(int n) { if (n < 0) { throw new IllegalArgumentException("Факториал не может быть рассчитан для отрицательных чисел"); } if (n == 0 || n == 1) { return 1; } return n * factorial(n - 1); } }<p>Запустите тест снова. Если вы всё сделали правильно, то он пройдёт успешно:</p>
79
<em>Скриншот: Skillbox Media</em><p>Поздравляем! Вы написали приложение, используя метод TDD для тестирования и разработки.</p>
79
<em>Скриншот: Skillbox Media</em><p>Поздравляем! Вы написали приложение, используя метод TDD для тестирования и разработки.</p>
80
<a>Научитесь: Профессия Java-разработчик + ИИ Узнать больше</a>
80
<a>Научитесь: Профессия Java-разработчик + ИИ Узнать больше</a>