Параметризованный жасмин unit test
Хорошо, как парень С# NUnit, это может быть странно.
Но делает ли жасмин параметризованным unit test?
Я не уверен, что это противоречит "объявить" и "это", чтобы сделать чтение понятным для не-программистов.
Я видел некоторые сторонние плагины, но они вроде старые, не уверен, что он добавлен в жасмин.
Если я хочу использовать плагин
Просто чтобы помочь любому, кто найдет это в будущем, мне сказали на форуме жасмина. Нет никакой первой поддержки класса для параметризованных тестов внутри самого Жасмина.
Ответы
Ответ 1
На основе ответа piotrek и статьи Параметрированное тестирование в Javascript, вы можете также используйте следующий подход, который использует синтаксис ES6:
[
['abc', 3],
['ab', 2],
['', 0],
].forEach(([string, expectedLength]) => {
it(`should return length ${expectedLength} for string "${string}"`, () => {
expect(string.length).toBe(expectedLength);
});
});
Я тестировал его с помощью тестовой среды Jest, но он также должен работать с Jasmine.
Ответ 2
Лучшее решение (особенно если вы используете TypeScript)
Другое решение - использовать Массив объектов вместо Массив массивов. Это подходит лучше, если вы используете какую-то систему ввода, например TypeScript.
Тип вопроса
Представьте, что у вас есть следующий параметризованный тест:
it('action(value) should reset the forms pool only if value is true', () => {
[
[true, 1],
[false, 0],
].forEach(([value, calledTimes]) => {
spyResetFormsPool.calls.reset();
component.action(value); // type error #1
expect(spyResetFormsPool).toHaveBeenCalledTimes(calledTimes); // type error #2
});
});
с TypeScript он не скомпилируется, что приводит к двум ошибкам:
ошибка №1:
ошибка TS2345: аргумент типа 'номер | boolean 'нельзя назначить параметру типа' boolean '.
ошибка № 2:
ошибка TS2345: аргумент типа 'номер | логическое значение 'не присваивается параметру типа' число '. Типа true не присваивается типу "число".
Это потому, что TypeScript видит массив из числа | булево.
Мы могли бы быстро решить это предупреждение, используя явное приведение:
it('action(value) should reset the forms pool only if value is true', () => {
[
[true, 1],
[false, 0],
].forEach(([value, calledTimes]) => {
spyResetFormsPool.calls.reset();
component.action(value as boolean); // necessary cast
expect(spyResetFormsPool).toHaveBeenCalledTimes(calledTimes as number); // necessary cast
});
});
однако это решение не очень хорошее.
Решение
Лучше использовать массив объектов, поэтому типы по умолчанию корректно обрабатываются и не требуется явное приведение:
it('action(value) should reset the forms pool only if value is true', () => {
[
{ value: true, calledTimes: 1 },
{ value: false, calledTimes: 0 },
].forEach(({ value, calledTimes }) => {
spyResetFormsPool.calls.reset();
component.action(value);
expect(spyResetFormsPool).toHaveBeenCalledTimes(calledTimes);
});
});
Вы хотите использовать for
вместо forEach
(лично я нахожу его более читабельным)? Это также возможно:
it('action(value) should reset the forms pool only if value is true', () => {
for (const {value, calledTimes} of [
{value: true, calledTimes: 1},
{value: false, calledTimes: 0},
]) {
spyResetFormsPool.calls.reset();
component.action(value);
expect(spyResetFormsPool).toHaveBeenCalledTimes(calledTimes);
}
});
В качестве альтернативы, вы также можете переместить it
внутри цикла. Когда я делаю это, я обычно добавляю testId
к каждому объекту, чтобы я мог отслеживать, какие тесты провалились:
for (const {value, calledTimes} of [
{ testId: 1, value: true, calledTimes: 1 },
{ testId: 2, value: false, calledTimes: 0 },
]) {
it('action(value) should reset the forms pool only if value is true [${testId}]', () => {
spyResetFormsPool.calls.reset();
component.action(value);
expect(spyResetFormsPool).toHaveBeenCalledTimes(calledTimes);
});
}
Ответ 3
Я не работал с жасмином с давних пор, но было довольно легко добавить параметризованные тесты:
['abc', 3,
'ab', 4,
'', 0].
it('should contain string length', function(string, expected){
expect(string.length).toBe(expected);
});
всего несколько строк кода инфраструктуры:
Array.prototype.it = function(description, testCaseFunction) {
_(this)
.chunk(testCaseFunction.length)
.each(function(innerArray){
it(description + ' ' + JSON.stringify(innerArray), function(){
testCaseFunction.apply(this, innerArray);
});
})
.value();
};
в зависимости от вашего желаемого синтаксиса и желания изменить объекты js по умолчанию, у вас есть много вариантов: http://blog.piotrturski.net/2015/04/jasmine-parameterized-tests.html
Ответ 4
Вы можете использовать следующее соглашение для повышения читабельности:
const testCases = [
{actualValue: true, expectedValue: true},
{actualValue: false, expectedValue: false}
]
testCases.forEach(({actualValue, expectedValue}) => {
it('should be the same given: ${actualValue} and expected :${expectedValue} values', () => {
expect(actualValue).toBe(expectedValue)
})
})
Вы увидите следующие тестовые случаи для запуска:
Test Results
+ should be the same given: true and expected: true values
+ should be the same given: false and expected: false values
Ответ 5
Итак, я начал комбинировать:
- YAML с использованием js-yaml
- jasminejs
- Машинопись
чтобы создать то, что я считаю читабельными параметризованными тестами, такими как это:
import YamlTableReader, {fixtureData, TestData} from "./YamlTableReader";
describe("TestSuite", () => {
describe("Real TestCase with Data Fixture", () => {
// now using tagged template-string to auto convert into YamlTableReader.
var testdata = fixtureData '
| ID | Value1 | Value2 | Squared |
| 0 |1 | 1 | 1 |
| 1 |2 | 2 | 4 |
| 2 |3 | 3 | 91 |
';
// This actually creates a test for each row of the table above
testdata.describeEach("Square Test","[ID={ID}]:{Value1} x {Value2} should be equal to {Squared}",
(row: {Value1: number, Value2: number, Squared: number}) => {
expect((row.Value1 * row.Value2)).toBe(row.Squared)
}
);
});
Запуск этого даст следующие результаты:
Failures:
1) TestSuite 2 Real TestCase with Data Fixture Square Test : [ID=2]:3 x 3 should be equal to 91
Message:
Expected 9 to be 91.
Источники: https://github.com/deicongmbh/jasmine-param-tests