You signed in with another tab or window.Reload to refresh your session.You signed out in another tab or window.Reload to refresh your session.You switched accounts on another tab or window.Reload to refresh your session.Dismiss alert
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.Learn more about bidirectional Unicode characters
Коли ми пишемо функцію, ми можемо уявити, як її будуть використовувати - які параметридають який результат.
Коли ми пишемо функцію, ми можемо уявити як її будуть використовувати - які параметридаватимуть який результат.
Під час розробки ми можемо перевірити функцію, запустивши її таперевіряючи фактичний результат з очікуваним. Наприклад, ми можемо робити це у консолі.
Під час розробки ми можемо перевірити функцію запустивши її тазвіривши фактичний результат з очікуваним. Наприклад, ми можемо робити це у консолі.
Якщо результат невірний -- ми можемо підправити код, запустити її знову, перевірити результат знову, і так до тих пір, поки вона не працюватиме вірно.
Якщофактичнийрезультат невідповідає очікуваному -- ми можемо підправити код, запустити її знову, перевірити результат знову, і так до тих пір, поки вона не працюватиме вірно.
Але такі ручні "повторні запуски" недосконалі.
**Тестуючи код вручну, можна легко щось упустити.**
Наприклад, ми створили функцію `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 DownExpand Up
@@ -128,7 +128,7 @@ function pow(x, n) {
## Вдосконалення специфікації
Те, що ми зробили, це, безумовно, обман. Функція не працює: спроба обчислити `pow (3,4) 'дала б неправильний результат, але тести проходять.
Те, що ми зробили, це, безумовно, обман. Функція не працює: спроба обчислити `pow (3,4)`дала б неправильний результат, але тести проходять.
... Але ситуація досить типова, це відбувається на практиці. Тести проходять, але функція працює неправильно. Наша специфіка недосконала. Нам потрібно додати більше випадків використання.
Expand DownExpand 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 DownExpand Up
@@ -296,7 +296,7 @@ describe("test", function() {
[edit src="beforeafter" title="Відкрити приклад в пісочниці."]
Як правило, `beforeEach/afterEach` і `before/after` використовуються для виконання ініціалізації, скидання лічильників або ще для чогось між тестами (або групами тестів).
Як правило, `beforeEach`/`afterEach` і `before`/`after` використовуються для виконання ініціалізації, скидання лічильників або ще для чогось між тестами (або групами тестів).
- `assert.isTrue(value)` -- перевіряє, що `value === true`
- `assert.isFalse(value)` -- перевіряє, що `value === false`
- ...повний список знаходиться в [документації](https://chaijs.com/api/assert/)
Expand Down
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.