В промежутке между переквалификацией с 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); }); });
).
Бред оказывается, как в названии, так и в самом тесте.
Вот список вопросов, которые помогут мне создать четкие и простые спецификации:
- Какие данные испытаний?
- Каков контекст тестирования?
- Какие случаи необходимо охватить?
- Как можно сгруппировать эти случаи?
- поле ввода флажка
- Пользователь нажимает на флажок
- Случаи:
- Состояние меняется до вызова обработчика кликов
- Состояние меняется на отмечено, если флажок не установлен.
- Состояние меняется на «не отмечено», если флажок установлен.
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 - запускает тесты во вложенном контексте
- включить примеры - запускает тесты в текущем контексте
- включитьПримерыДля - запускает тесты в текущем контексте
// 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
-
Оорт, Ян Хендрик
19 Oct, 24 -
Переезд В Индию
19 Oct, 24 -
Asp.net 4.0: Руководство Разработчика
19 Oct, 24 -
Самый Большой Аргумент Против Mysql?
19 Oct, 24 -
Stm32 И Usb-Hid – Это Просто
19 Oct, 24