Как написать корректный тест на калькулятор JS
Калькулятор делает простые операции, но еще умеет работать с римскими числами. Суть в том чтобы выводить информацию о всех значениях динамически в лог. По типу
Test №1 Не пройден. Проверьте сложение арабских чисел. На выход была подана строка:
1 + 1Ожидаемый результат:2Полученный результат:null
Пока тест выглядит так:
test('должен работать с десятичными числами (сложение)', () => {
expect(calculator('1 + 1')).toBe('2')
expect(calculator('1 + 2')).toBe('3')
expect(calculator('4 + 3')).toBe('7')
expect(calculator('10 + 10')).toBe('20')
})
test('должен работать с десятичными числами (вычитание)', () => {
expect(calculator('10 - 1')).toBe('9')
expect(calculator('5 - 4')).toBe('1')
expect(calculator('4 - 4')).toBe('0')
expect(calculator('1 - 10')).toBe('-9')
expect(calculator('4 - 5')).toBe('-1')
})
А хотелось бы чтобы он выводил как в примере выше с описанием того, что было подано и тд
Код калькулятора +- такой:
function calculator(str) {
const split = str.split(" ");
const str1 = split[0];
const str2 = split[2];
const op = split[1];
if(split.length != 3)
throw new Error("Incorrect");
const number1 = +str1;
const number2 = +str2;
if(!isNaN(number1) && !isNaN(number2)) {
if(!Number.isInteger(number1) || !Number.isInteger(number2))
throw new Error("Incorrect");
if(number1 < 1 || number1 > 10 || number2 < 1 || number2 > 10)
throw new Error("Incorrect");
return calculate(number1, number2, op);
} else if(isNaN(number1) && isNaN(number2)) {
const rom1 = roman2arabic(str1);
const rom2 = roman2arabic(str2);
if(rom1 < 1 || rom1 > 10 || rom2 < 1 || rom2 > 10)
throw new Error("Incorrect");
const result = calculate(rom1, rom2, op);
if(result > 0)
return arabic2roman(result);
else if(result < 1)
return "";
}
throw new Error("Incorrect");
}
function calculate(num1, num2, oprt) {
switch (oprt) {
case "+":
return String(Math.trunc(num1 + num2));
case "-":
return String(Math.trunc(num1 - num2));
case "*":
return String(Math.trunc(num1 * num2));
case "/":
return String(Math.trunc(num1 / num2));
default:
throw new Error("Incorrect");
}
}
const digits = {
C: 100,
XC: 90,
L: 50,
XL: 40,
X: 10,
IX: 9,
V: 5,
IV: 4,
I: 1,
};
function roman2arabic(str) {
if(!/^[IVXLCDMZ]+$/i.test(str))
throw new Error("Incorrect roman number format: " + str);
return str
.toUpperCase()
.split("")
.reduce(function (r, v, i, arr) {
const [a, b, c] = [
digits[arr[i]],
digits[arr[i + 1]],
digits[arr[i + 2]],
];
if (b && c && a <= b && b < c)
throw new Error("Incorrect roman number format: " + str);
return b > a ? r - a : r + a;
}, 0);
}
function arabic2roman(num) {
if(!/^\-?\d+$/.test(num + ""))
throw new Error("Can`t convert that arabic numeric to roman: " + num);
if(num < 1)
return "";
let result = "";
for (let key in digits)
while (num >= digits[key]) {
result += key;
num -= digits[key];
}
return result;
}
module.exports = calculator
Ответы (2 шт):
test('должен работать с римскими числами (сложение)', () => {`введите сюда код`
expect(calculator('I + I')).toBe('II');
expect(calculator('I + II')).toBe('III');
expect(calculator('IV + III')).toBe('VII');
expect(calculator('X + X')).toBe('XX');
expect(calculator('X + IX')).toBe('XIX');
});
test('должен работать с римскими числами (вычитание)', () => {
expect(calculator('X - I')).toBe('IX');
expect(calculator('V - IV')).toBe('I');
expect(calculator('IV - IV')).toBe('');
expect(calculator('I - X')).toBe('');
expect(calculator('IV - V')).toBe('');
});
test('должен работать с римскими числами (умножение)', () => {
expect(calculator('X * X')).toBe('C');
expect(calculator('IV * X')).toBe('XL');
expect(calculator('V * I')).toBe('V');
expect(calculator('V * V')).toBe('XXV');
});
test('должен работать с римскими числами (деление)', () => {
expect(calculator('X / I')).toBe('X');
expect(calculator('VI / II')).toBe('III');
expect(calculator('V / IV')).toBe('I');
expect(calculator('II / IV')).toBe('');
});
test('должен выбрасывать ошибку на некорректных данных', () => {
expect(() => calculator('')).toThrowError();
expect(() => calculator(' ')).toThrowError();
expect(() => calculator(' ')).toThrowError();
expect(() => calculator('4')).toThrowError();
expect(() => calculator('+')).toThrowError();
expect(() => calculator('++1')).toThrowError();
expect(() => calculator('V')).toThrowError();
expect(() => calculator('3 % 4')).toThrowError();
expect(() => calculator('1 + 1 + 1')).toThrowError();
expect(() => calculator('11 + 1')).toThrowError();
expect(() => calculator('1 + 11')).toThrowError();
expect(() => calculator('XI + I')).toThrowError();
expect(() => calculator('I + XI')).toThrowError();
expect(() => calculator('1 + V')).toThrowError();
expect(() => calculator('I + 1')).toThrowError();
expect(() => calculator('5 / 0')).toThrowError();
expect(() => calculator('0 + 1')).toThrowError();
expect(() => calculator('1 + 0')).toThrowError();
});
Рекомендую каждое отдельное выполнение функции calculator сделать отдельным тест-кейсом. Чтобы группировать тест-кейсы, использовал конструкцию describe() и test.each(). Обратите внимание, вызовы describe можно вкладывать друг в друга.
describe('работа с десятичными числами', () => {
describe('сложение', () => {
test.each`
expr | expected
${'1 + 1'} | ${'2'}
${'1 + 2'} | ${'3'}
${'4 + 3'} | ${'7'}
${'10 + 10'} | ${'20'}
`('результат $expr должен быть равен $expected', ({expr, expected}) => {
expect(calculator(expr)).toBe(expected)
});
});
describe('вычитание', () => {
test.each`
expr | expected
${'10 - 1'} | ${'9'}
${'5 - 4'} | ${'1'}
${'4 - 4'} | ${'0'}
${'1 - 10'} | ${'-9'}
${'4 - 5'} | ${'-1'}
`('результат $expr должен быть равен $expected', ({expr, expected}) => {
expect(calculator(expr)).toBe(expected)
});
});
});
describe('работа с римскими числами', () => {
//...
});
Вот что получается на выходе:
PASS ru-so/calculator.test.js
работа с десятичными числами
сложение
√ результат 1 + 1 должен быть равен 2 (2 ms)
√ результат 1 + 2 должен быть равен 3 (1 ms)
√ результат 4 + 3 должен быть равен 7
√ результат 10 + 10 должен быть равен 20
вычитание
√ результат 10 - 1 должен быть равен 9
√ результат 5 - 4 должен быть равен 1
√ результат 4 - 4 должен быть равен 0
√ результат 1 - 10 должен быть равен -9 (4 ms)
√ результат 4 - 5 должен быть равен -1