Jasmine Dry: Правильно Ли Ты Пишешь Тесты?

В промежутке между переквалификацией с Back-end программиста на Front-end мне пришлось писать код для приложения RoR (да, были тесты).

Что мне показалось интересным, так это своеобразная атмосфера сообщества Ruby-писателей, которые очень строго относятся к написанию кода и если ты пишешь плохо, тебе могут сломать пальцы и они тебя не простят. После всего код должен быть максимально простым и читабельным .

Это же правило касается и тестов (как по мне, они должны быть на порядок проще самого кода).

Кроме того, у тестов есть свое золотое правило — Одно ожидание на каждый тест .

Не надо писать кучу ожидать/утверждать/должен звонки в одном тесте, просто перестаньте это делать! И не забывайте, что тесты — это тоже код, и копировать вставить - плохая практика.



Что такое плохой тест

Разобравшись в версии 3.0 Knockout.js, я решил посмотреть тесты в надежде найти хоть какое-нибудь упоминание о новом свойстве.

после внутри креплений.

Честно говоря, меня возмутила сложность написанных тестов.

Плохой тест

  
  
  
  
   

describe('Binding: Checked', function() { beforeEach(jasmine.prepareTestNode); it('Triggering a click should toggle a checkbox\'s checked state before the event handler fires', function() { testNode.innerHTML = "<input type='checkbox' />"; var clickHandlerFireCount = 0, expectedCheckedStateInHandler; ko.utils.registerEventHandler(testNode.childNodes[0], "click", function() { clickHandlerFireCount++; expect(testNode.childNodes[0].

checked).

toEqual(expectedCheckedStateInHandler); }) expect(testNode.childNodes[0].

checked).

toEqual(false); expectedCheckedStateInHandler = true; ko.utils.triggerEvent(testNode.childNodes[0], "click"); expect(testNode.childNodes[0].

checked).

toEqual(true); expect(clickHandlerFireCount).

toEqual(1); expectedCheckedStateInHandler = false; ko.utils.triggerEvent(testNode.childNodes[0], "click"); expect(testNode.childNodes[0].

checked).

toEqual(false); expect(clickHandlerFireCount).

toEqual(2); }); });

Если не учитывать, что все директивы ( описывать И это ) являются частью спецификации, то из заголовка невозможно понять смысл теста ( он вызывает щелчок, должен.

).

Бред оказывается, как в названии, так и в самом тесте.

Вот список вопросов, которые помогут мне создать четкие и простые спецификации:

  1. Какие данные испытаний?
  2. Каков контекст тестирования?
  3. Какие случаи необходимо охватить?
  4. Как можно сгруппировать эти случаи?
Для приведенного выше примера:
  1. поле ввода флажка
  2. Пользователь нажимает на флажок
  3. Случаи:
    1. Состояние меняется до вызова обработчика кликов
    2. Состояние меняется на отмечено, если флажок не установлен.

    3. Состояние меняется на «не отмечено», если флажок установлен.

Теперь все то же самое, только на английском языке: Легко читаемый тест.

describe('Binding: Checked', function() { beforeEach(jasmine.prepareTestNode); describe("when user clicks on checkbox", function () { beforeEach(function () { testNode.innerHTML = "<input type='checkbox' />"; this.checkbox = testNode.childNodes[0]; this.stateHandler = jasmine.createSpy("checked handler"); this.checkbox.checked = false; ko.utils.registerEventHandler(this.checkbox, "click", function() { this.stateHandler(this.checkbox.checked); }.

bind(this)); ko.utils.triggerEvent(this.checkbox, "click"); }) it ("changes state before event handler is triggered", function () { expect(this.stateHandler).

toHaveBeenCalledWith(true); }) it ("marks checkbox if it's not marked", function () { expect(this.checkbox.checked).

toBe(true) }) it ("unmarks checkbox if it's marked", function () { this.checkbox.checked = true; ko.utils.triggerEvent(this.checkbox, "click"); expect(this.checkbox.checked).

toBe(false); }) }) })

Настраивать - сложные, тесты - простые.

Идеальный вариант — тест, содержащий один вызов функции ожидать .



Меньше кода, больше тестов

Когда вы впервые встретились Жасмин Я понимал, что это не идеально, но не найдя возможности создания групповых спеков, я запаниковал и бросился за помощью в Google .

К моему большому разочарованию, он также не знал ответа, который бы меня устроил.

Мне самому пришлось копаться в темных глубинах Жасмин и найти решение.

Давайте представим, что существует JavaScript ++, который имеет 2 класса Множество И Набор с общим интерфейсом ( размер И содержит ).

Теперь вам нужно покрыть их тестами без дублирования кода! Определим общие тесты для наших коллекций:

sharedExamplesFor("collection", function () { beforeEach(function () { this.sourceItems = [1,2,3]; this.collection = new this.describedClass(this.sourceItems); }) it ("returns proper size", function () { expect(this.collection.size()).

toBe(this.sourceItems.length); }) // another specs it ("returns true if contains item", function () { expect(this.collection.contains(this.sourceItems[0])).

toBe(true); }) })

По аналогии с Rspec , хотелось бы иметь возможность подключать спецификации одним из способов:

  • itBehavesLike - запускает тесты во вложенном контексте
  • itShouldBehaveLike - запускает тесты во вложенном контексте
  • включить примеры - запускает тесты в текущем контексте
  • включитьПримерыДля - запускает тесты в текущем контексте
Примечание :itShouldBehaveLike и includeExamplesFor — существуют только для улучшения читаемости тестов

// array_spec.js describe("Array", function () { beforeEach(function () { this.describedClass = Array; }) itBehavesLike("collection"); //another specs }) // set_spec.js describe("Set", function () { beforeEach(function () { this.describedClass = Set; }) itBehavesLike("collection"); //another specs });

Я также обычно создаю функцию контекст (Элиас для описывать ), чтобы улучшить читабельность спецификации.

Исходный код реализации общей спецификации

// spec_helper.js var sharedExamples = {}; window.sharedExamplesFor = function (name, executor) { sharedExamples[name] = executor; }; window.itBehavesLike = function (sharedExampleName) { jasmine.getEnv().

describe("behaves like " + sharedExampleName, sharedExamples[sharedExampleName]); }; window.includeExamplesFor = function (sharedExampleName) { var suite = jasmine.getEnv().

currentSuite; sharedExamples[sharedExampleName].

call(suite); }; window.context = window.describe; window.includeExamples = window.includeExamplesFor; window.itShouldBehaveLike = window.itBehavesLike;

Теги: #жасмин #JavaScript #лучшие практики #JavaScript

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.