Короткая заметка про разные стили работы тестовых фреймворков в JS (в целом актуально и не только для JS)
Есть 2 типа тестовых тулзов: spec и tap. Spec - это когда мы тесты обозначаем специальной функцией и когда она выкидывает исключение - мы считаем что тест упал. Если же исключение не было выкинуто - тест прошел. Tap - это когда есть специальное API для проверок и проверки либо проходят либо нет.
Типичный пример в spec-подходе:
describe('account', () => {
it('has a balance of zero when first created', () => {
// if this throws, the test fails
expect(new Account().balance).to.equal(0)
})
it('has an empty list of initial addresses', () => {
expect(new Account().addresses).to.match([])
})
})
Типичный пример в tap-подходе:
t.test('account', async t => {
const a = new Account()
t.equal(a.balance, 0, 'balance of zero when first created')
t.match(a.addresses, [], 'empty list of addresses')
t.test('credits', async t => {
a.credit(100)
t.equal(a.balance, -100, 'negative balance after credit')
a.debit(200)
t.equal(a.balance, 100, 'positive balance after debit')
})
})
В первом сниппете кода границы тесты - это describe и it.
Во втором же сниппете используется объект t, который умеет делать проверки и композировать их через test. При этом "тестов" в привычном понимании там нет, только проверки. Минимальный tap тест выглядит так t.ok(cond, message)
То есть, разница подходов - разница в абстракции, вокруг которых они крутятся. Для spec - это тесты, для tap - проверки.
Автор также указывает на разницу, что в spec-подходе it и describe определяются тест-ранером (а значит нельзя запустить тесты на чисто nodejs) и обязательно нужно выделять describe => it, но, кажется что в реальности это не так (т.к. все таки есть тулы, где эти функции нужно импортировать явно, а тесты могут запускаться без отдельного тест-ранера)