Skip to content

Fix testing mocha #692

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 17 additions & 17 deletions 1-js/03-code-quality/05-testing-mocha/article.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,17 @@

## Навіщо нам потрібні тести?

Коли ми пишемо функцію, ми можемо уявити, як її будуть використовувати - які параметри дають який результат.
Коли ми пишемо функцію, ми можемо уявити як її будуть використовувати - які параметри даватимуть який результат.

Під час розробки ми можемо перевірити функцію, запустивши її та перевіряючи фактичний результат з очікуваним. Наприклад, ми можемо робити це у консолі.
Під час розробки ми можемо перевірити функцію запустивши її та звіривши фактичний результат з очікуваним. Наприклад, ми можемо робити це у консолі.

Якщо результат не вірний -- ми можемо підправити код, запустити її знову, перевірити результат знову, і так до тих пір, поки вона не працюватиме вірно.
Якщо фактичний результат не відповідає очікуваному -- ми можемо підправити код, запустити її знову, перевірити результат знову, і так до тих пір, поки вона не працюватиме вірно.

Але такі ручні "повторні запуски" недосконалі.

**Тестуючи код вручну, можна легко щось упустити.**

Наприклад, ми створили функцію `f`. Перевірили деякий код, тестуємо: `f(1)` працює, але `f(2)` не працює. Ми підправляємо код і тепер `f(2)` працює. Здається, що справу зроблено? Але ми забули перевірити чи `f(1)` досі працює. Це може призвести до помилки.
Наприклад, ми створили функцію `f`. Перевірили деякий код. Тестуємо: `f(1)` працює, але `f(2)` не працює. Ми підправляємо код і тепер `f(2)` працює. Здається ніби справу зроблено. Але ми забули перевірити чи `f(1)` досі працює. Це може призвести до помилки.

Це дуже типово. Коли ми щось розробляємо, ми пам’ятаємо про багато можливих випадків використання. Але не треба очікувати, що програміст перевірятиме їх усі вручну після кожної зміни. Так стає легко виправити щось одне і зламати інше.

Expand All @@ -24,17 +24,17 @@

Розпочнімо з техніки під назвою [Керована поведінкою розробка](https://uk.wikipedia.org/wiki/Керована_поведінкою_розробка) або коротко, BDD (від англ. behavior-driven development).

**BDD це три в одному: і тести, і документація, і приклади використання.**
**BDD -- це три в одному: і тести, і документація, і приклади використання.**

Щоб зрозуміти BDD, ми розглянемо реальний приклад розробки.

## Розробка функції піднесення до степеня - "pow": специфікація

Припустимо, ми хочемо зробити функцію `pow(x, n)`, яка піднесе `x` до степеня `n`. Ми припускаємо, що `n≥0`.

Це завдання є просто прикладом - в JavaScript є оператор `**`, що підносить до степеня, але в цьому прикладі ми зосередимось на процесі розробки, який потім можна також застосовувати й для складніших завдань.
Це завдання є просто прикладом. В JavaScript це саме може зробити оператор `**`, але ми використаємо цей приклад щоб зосередитись на процесі розробки, який потім можна також застосовувати й для складніших завдань.

Перш ніж створити код для функції `pow ', ми можемо уявити, що вона повинна виконувати, і описати її.
Перш ніж створити код для функції `pow`, ми можемо уявити, що вона повинна виконувати, і описати її.

Такий опис називається *специфікацією*, і він описує приклади використання функції разом з тестами, наприклад:

Expand All @@ -59,17 +59,17 @@ describe("pow", function() {
`assert.equal(value1, value2)`
: Код всередині блоку `it` має виконуватись без помилок, якщо реалізація правильна.

Функції `assert.*` використовуються для перевірки того, що функція `pow` працює, як ми очікуємо. В нашому випадку, ми використовуємо одну з них -- `assert.equal`, вона порівнює аргументи і сповіщає про помилку, якщо вони відрізняються. Тут вона перевіряє, що результат `pow(2, 3)` дорівнює `8`. Є також інші способи порівняння та перевірки, які ми розглянемо пізніше.
Функції `assert.*` використовуються для перевірки того, що функція `pow` працює, як ми очікуємо. В нашому випадку, ми використовуємо одну з них -- `assert.equal`, вона порівнює аргументи і сповіщає про помилку, якщо вони відрізняються. Тут вона перевіряє чи результат `pow(2, 3)` дорівнює `8`. Є також інші способи порівняння та перевірки, які ми розглянемо пізніше.

Специфікацію можна виконати, і вона автоматично виконає тести, вказані у блоках `it`. Ми розглянемо це далі.

## Процес розробки

Зазвичай, процес розробки має наступний вигляд:

1. Пишуть первинну специфікацію з тестами основного функціонала.
1. Пишуть первинну специфікацію з тестами основного функціоналу.
2. Створюється початкова реалізація.
3. Щоб перевірити, чи вона працює, ми використовуємо тестовий фреймворк [Mocha](https://mochajs.org/) (більш детально нижче), який виконує специфікацію. Якщо функціонал не завершено -- виводяться повідомлення про помилки. Ми робимо виправлення до тих пір, поки не матимемо повністю робочий код.
3. Щоб перевірити, чи вона працює, ми запускаємо фреймворк для тестів [Mocha](https://mochajs.org/) (більш детально нижче), який виконує специфікацію. Якщо функціонал не завершено -- виводяться повідомлення про помилки. Ми робимо виправлення до тих пір, поки наш код не почне працювати як слід.
4. Тепер ми маємо початкову реалізацію з тестами.
5. Ми додаємо більше способів використання до специфікації, навіть таких, що поки що не підтримуються реалізацією. Виконання тестів знову завершиться невдачею.
6. Переходимо на 3-й пункт, змінюємо реалізацію, щоб вона відповідала тестам і вони не повертали повідомлення про помилку.
Expand All @@ -86,7 +86,7 @@ describe("pow", function() {
Тут у посібнику ми будемо використовувати такі бібліотеки JavaScript для тестів:

- [Mocha](https://mochajs.org/) -- базовий фреймворк: він забезпечує нас загальними функціями для тестування, в тому числі `describe` та `it`, а також головною функцією, що виконує тести.
- [Chai](https://chaijs.com) -- бібліотека для порівняння і оцінки роботи коду. Вона дозволяє використовувати безліч різних порівнянь, але поки що нам потрібне лише функція порівняння `assert.equal`.
- [Chai](https://chaijs.com) -- бібліотека для порівняння і оцінки роботи коду. Вона дозволяє використовувати безліч різних порівнянь, але поки що нам потрібна лише функція порівняння `assert.equal`.
- [Sinon](https://sinonjs.org/) -- бібліотека для "шпигування" за функціями, емуляції вбудованих функцій тощо, нам це знадобиться набагато пізніше.

Ці бібліотеки підходять як для тестування в браузері, так і на стороні сервера. Тут ми розглянемо варіант тестування в браузері.
Expand All @@ -99,7 +99,7 @@ describe("pow", function() {
Сторінку можна розділити на п’ять частин:

1. `<head>` містить сторонні бібліотеки та стилі для тестів.
2. `<script>` містить код функції, яку треба тестувати, в нашому випадку - код функції `pow`.
2. `<script>` з функцією, яку треба тестувати, в нашому випадку функцією `pow`.
3. Тести - в нашому випадку зовнішній скрипт `test.js`, який містить специфікацію `describe("pow", ...)`, описану вище.
4. HTML елемент `<div id="mocha">` буде використаний фреймворком Mocha для виведення результатів.
5. Тести запускаються командою `mocha.run()`.
Expand Down Expand Up @@ -128,7 +128,7 @@ function pow(x, n) {

## Вдосконалення специфікації

Те, що ми зробили, це, безумовно, обман. Функція не працює: спроба обчислити `pow (3,4) 'дала б неправильний результат, але тести проходять.
Те, що ми зробили, це, безумовно, обман. Функція не працює: спроба обчислити `pow (3,4)` дала б неправильний результат, але тести проходять.

... Але ситуація досить типова, це відбувається на практиці. Тести проходять, але функція працює неправильно. Наша специфіка недосконала. Нам потрібно додати більше випадків використання.

Expand Down Expand Up @@ -261,8 +261,8 @@ describe("pow", function() {

В майбутньому ми можемо додати ще `it` та `describe` на верхньому рівні з власними допоміжними функціями, в яких не буде доступу до `makeTest`.

````smart header="`before/after` та `beforeEach/afterEach`"
Ми можемо налаштувати `before/after` функції, які виконуються перед/після запуску тестів, а також функції `beforeEach/afterEach`, які виконуються перед/після *кожного* `it`.
````smart header="`before`/`after` та `beforeEach`/`afterEach`"
Ми можемо налаштувати `before`/`after` функції, які виконуються перед/після запуску тестів, а також функції `beforeEach`/`afterEach`, які виконуються перед/після *кожного* `it`.

Наприклад:

Expand Down Expand Up @@ -296,7 +296,7 @@ describe("test", function() {

[edit src="beforeafter" title="Відкрити приклад в пісочниці."]

Як правило, `beforeEach/afterEach` і `before/after` використовуються для виконання ініціалізації, скидання лічильників або ще для чогось між тестами (або групами тестів).
Як правило, `beforeEach`/`afterEach` і `before`/`after` використовуються для виконання ініціалізації, скидання лічильників або ще для чогось між тестами (або групами тестів).
````

## Розширення специфікації
Expand Down Expand Up @@ -342,7 +342,7 @@ describe("pow", function() {

- `assert.equal(value1, value2)` -- перевіряє рівність `value1 == value2`.
- `assert.strictEqual(value1, value2)` -- перевіряє сувору рівність `value1 === value2`.
- `assert.notEqual`, `assert.notStrictEqual` -- зворотня перевірка до вищевказаної.
- `assert.notEqual`, `assert.notStrictEqual` -- інвертована перевірка (`!=`/`!==`).
- `assert.isTrue(value)` -- перевіряє, що `value === true`
- `assert.isFalse(value)` -- перевіряє, що `value === false`
- ...повний список знаходиться в [документації](https://chaijs.com/api/assert/)
Expand Down