Обеспечение изолированного выполнения тестов с использованием Chai Spies
Суть
Используйте крючки beforeEach
и afterEach
мокко для настройки и сброса шпиона:
// Set up the spy beforeEach(function() { // chai.spy.on([source code], [function names], [mock function]) chai.spy.on(domUpdates, ['displayName'], () => true); }) // Reset and tear down the spy afterEach(function() { chai.spy.restore(domUpdates); })
При этом ни один тест (блок it
) не будет зависеть от другого теста или порядка тестов. Как нам туда добраться? Вот еще немного предыстории реализации выше:
Почему шпионы?
В этом посте я предполагаю, что вы используете мокко и чай и что вы уже используете библиотеку chai-spies для шпиона в своем тесте.
В этом примере есть объект domUpdates
, содержащий функции, выполняющие манипуляции с DOM. Функция domUpdates.displayName
вызывается внутри другой функции с именем changeName
(метод класса):
// domUpdates.js export default { displayName: function(name) { document.querySelector('#name-display').innerText = name; } } // Person.js class Person { constructor(name = 'Sam'){ this.name = name; } changeName(newName) { this.name = newName; domUpdates.displayName(this.name); } }
Без шпиона тестирование функции changeName
привело бы к ошибке от mocha:
ReferenceError: document is not defined
Добавить шпиона
Чтобы сохранить тестируемость метода changeName
, вы можете добавить шпиона для domUpdates.displayName
. Добавление шпиона в тесте выглядит так:
// test-file.js // (Import your other test setup here...) import spies from 'chai-spies'; chai.use(spies); // Add a spy for a specific function chai.spy.on(domUpdates, ['displayName'], () => true); describe('Change Name', function() { it('Change to a new name', function(){ let person = new Person('Sam'); changeName('Alex'); expect(person.name).to.equal('Alex');expect(domUpdates.
displayName).to.have.been.called(1); expect(domUpdates.
displayName).to.have.been.called.with(
'Alex');
}) it('Change to a new name with special characters', function(){ let person = new Person('Sam'); changeName('S@m'); expect(person.name).to.equal('S@m');expect(domUpdates.
displayName).to.have.been.called(1); expect(domUpdates.
displayName).to.have.been.called.with('
S@m');
}) })
Это должно работать. Проблема в том, что шпион не сбрасывается автоматически для каждого it
блока. Так что второй to.have.been.called(1)
потерпит неудачу как есть. Чтобы пройти, второй to.have.been.called()
должен быть to.have.been.called(2)
.
// This change would make the test pass it('Change to a new name with special characters', function(){ let person = new Person('Sam'); changeName('S@m'); expect(person.name).to.equal('S@m');expect(domUpdates.
displayName).to.have.been.called(2); expect(domUpdates.
displayName).to.have.been.called.with('
S@m');
})
И если мы добавим больше тестов с помощью этого шпиона, нам также потребуется увеличить следующие значения called()
. Если тесты каким-либо образом переупорядочиваются в файле, числа в to.have.been.called()
придется изменить. Это не изолированный тест, если значения в to.have.been.called()
меняются в зависимости от порядка тестов. Это кошмар испытаний!
Mocha Hooks и шпионское восстановление
Вот где могут помочь крючки Mocha и шпионский метод restore
! Перед каждым тестом настраивайте шпион. Затем после каждого теста убирайте шпиона так, чтобы to.have.been.called()
был изолирован от каждого блока it
.
Добавьте хуки в блок описания, содержащий тесты с использованием шпионов:
// Set up the spy beforeEach(function() { // chai.spy.on([source code], [function names], [mock function]) chai.spy.on(domUpdates, ['displayName'], () => true); }) // Reset and tear down the spy afterEach(function() { chai.spy.restore(domUpdates); })
Теперь тесты могут выполняться изолированно, а значения .called()
будут количеством вызовов функции только в блоке it
.
Вот и все! Chai Spies не моя любимая библиотека для шпионов, но это то, что я сделал, чтобы сделать тесты более дружелюбными.
Если вы ищете другие библиотеки, где вам нужен шпион, рассмотрите Синон или даже отойдите от мокко и рассмотрите встроенный функционал Jest. Я хотел бы услышать о том, как вы используете шпионов!