Покрытие кода — важный показатель того, насколько проект безопасен и надежен.
Что такое покрытие кода
В компьютерных программах покрытие кода относится к проценту исполняемого исходного кода, покрытого выполнением тестового примера, по отношению к общему исходному коду и часто используется для измерения того, является ли проект или программа безопасным и надежным.
Правила покрытия
Стандартные показатели покрытия делятся на следующие категории.
- Покрытие операторов. Выполняется ли каждый оператор в программе?
- Покрытие функций. Выполняется ли каждая функция в программе?
- Покрытие ветвей. Выполняется ли каждая ветвь в программе?
- Покрытие строк. Выполняется ли каждая строка кода в программе?
Рассмотрим следующие коды
function sum(x,y) { let z = 0; if(x>0 && y>0) { z = x + y } return z }
Мы написали тестовые примеры для проверки этой функции.
it("当传入 x 为1, y为1时,返回2", () => { expect(sum(1, 1)).equal(2); }); it("当传入 x 为1, y为0时,返回0", () => { expect(sum(1, 0)).equal(0); });
Когда приведенный выше тестовый пример будет выполнен, произойдет следующее
- Функция суммы выполняется, и покрытие функции составляет 100%.
- Каждая инструкция внутри функции суммы выполняется, например, когда мы выполняем сумму (1,1) и сумму (1,0) отдельно, покрытие оператора составляет 100%.
- Условие if и возврат z выполняются внутри функции суммы, например, покрытие ветвей составляет 100%, когда вы вызываете sum (2,1) и sum (0,0)
- Если каждая строка приведенного выше блока кода покрыта, включая символ}, покрытие строк составляет 100%.
Значение статистического покрытия кода
Покрытие кода — это мера полноты теста. Основная цель состоит в том, чтобы уменьшить вероятность ошибок кода и часто используется в следующих сценариях.
- Чтобы снизить вероятность появления ошибок в коде, особенно для важных проектов или библиотек, важно обеспечить высокий охват кода, чтобы у других было меньше шансов использовать ваш код с ошибками.
- измеряйте ход работы по тестированию и направляйте написание тестовых случаев, без метрик покрытия кода вы не можете знать, завершена ли ваша работа по тестированию или нет
Как вы измеряете покрытие кода?
Если вам нужно подсчитать покрытие кода файла «src/index.js», код «src/index.js» выглядит следующим образом.
function sum(x, y) { return x + y; }
Параллельно мы написали следующие тест-кейсы
const { sum } = require("src/index.js"); descripe("验证 sum 方法", () => { it("当传入 x 为1, y为1时,返回2", () => { expect(sum(1, 1)).equal(2); }); });
Если мы хотим подсчитать покрытие кода src/index.js, нам нужны исходные данные для описания основной информации кода в src/index.js, например, сколько функций, сколько операторов и сколько строк кода (эту информацию можно получить, скомпилировав исходный код в AST), а также для записи начального состояния каждой функции, каждого оператора (независимо от того, выполняется он или нет).
Здесь я определяю переменную c для ее описания, c — это объект, ключ — это путь к файл, а значением является базовая информация о коде, содержащемся в файле; fnMap представляет информацию о функции в src/index.js, а также является объектом, ключ — это значение, значение — это основная информация о функции (имя функции, объявления функции, тела функции и т. д.); statementMap представляет информацию об инструкции в файле src/index.js, который также является объектом, ключ — это значение, а значение — это информация о расположении инструкции; f указывает, выполняется ли функция, 0 означает, что она выполняется, а 1 означает, что она выполняется; s указывает, выполняется ли инструкция, 0 означает, что она выполняется, а 1 означает, что она выполняется. значит выполнено.
const c = { "src/index.js": { fnMap: { 0: { name: "sum", decl: { start: { line: 1, column: 9, }, end: { line: 1, column: 12, }, }, loc: { start: { line: 1, column: 19, }, end: { line: 3, column: 1, }, }, line: 1, }, }, statementMap: { 0: { start: { line: 2, column: 2, }, end: { line: 2, column: 15, }, }, }, s: { 0: 0, }, f: { 0: 0, } }, };
Затем нам нужно встроить приведенные выше данные в исходный код, чтобы при выполнении кода данные можно было изменить, и мы могли легко вычислить покрытие кода позже.
function sum(x, y) { c[fn][0]++; c[s][0]++ return x + y; }
Теперь при запуске тестового примера, если функция sum выполняется, c[fn][0] ++ и c[s] [0] ++ также выполняются, и значения атрибутов s и f в объекте уход изменился на 1 после выполнения
const c = { "src/index.js": { fnMap: { 0: { name: "sum", decl: { start: { line: 1, column: 9, }, end: { line: 1, column: 12, }, }, loc: { start: { line: 1, column: 19, }, end: { line: 3, column: 1, }, }, line: 1, }, }, statementMap: { 0: { start: { line: 2, column: 2, }, end: { line: 2, column: 15, }, }, }, s: { 0: 1, }, f: { 0: 1, }, }, };
Наконец, анализируя приведенные выше данные, мы видим только одну функцию с именем sum с ключом 0 и f [0] = 1 и только один оператор с ключом 0 и s [0 ] = 1, поэтому мы можем статистически определить, что Покрытие операторов в src/index.js составляет 100 %, а Покрытие функций равно 100 %.
Это основной принцип статистики покрытия кода. В реальных проектах нам не нужно анализировать код вручную и инструментировать исходный код счетчиками строк, есть готовые инструменты (например, Стамбул), которые сделают все вышеперечисленное за нас.
Если вы хотите узнать, как пользоваться инструментом, вы можете ознакомиться с проектом Стамбульский тест.
Поддержите меня
Писать не просто, если вам понравилась моя статья, подписывайтесь на меня и хлопайте в ладоши.