Это 125-я оригинальная статья без воды.Если вы хотите получить больше оригинальных статей, выполните поиск в общедоступном аккаунте и подпишитесь на нас~ Эта статья была впервые опубликована в блоге Zhengcaiyun:Как проводить фронтенд-тестирование
Как проводить фронтенд-тестирование
Для текущего фронтенд-проекта очень необходим стандартный завершенный проект, обычно модульное тестирование. Но часто мы просто заканчиваем проект и игнорируем его тестирование. Я думаю, что одна из больших причин в том, что многие люди недостаточно знают о модульном тестировании, поэтому я написал эту статью, с одной стороны, я надеюсь, что эта статья даст вам предварительное представление о модульном тестировании. С другой стороны, я надеюсь, что с помощью примеров кода вы овладеете практическими навыками написания модульных тестов.
Зачем нам нужно модульное тестирование для интерфейса?
-
Необходимость: в JavaScript отсутствует проверка типов, ошибки не могут быть обнаружены во время компиляции, а модульные тесты могут помочь вам протестировать множество исключений.
-
Правильность: тесты могут проверить правильность кода и убедиться, что вы знаете, прежде чем запускать его в жизнь.
-
Автоматизация: Хотя внутреннюю информацию можно распечатать через консоль, это разовая вещь, и следующий тест нужно начинать с нуля, поэтому эффективность не может быть гарантирована. Написав тест-кейсы, вы можете написать их один раз и запускать много раз.
-
Гарантированный рефакторинг: Скорость итерации продуктов в интернет-индустрии очень высока, и после итерации должен быть процесс рефакторинга кода Как мы можем гарантировать качество рефакторинга кода? С поддержкой тестовых случаев вы можете смело проводить рефакторинг.
статус-кво
Ниже приводится выдержка из выборочного обследования, основанного на следующем:
-
Разослать онлайн-анкету 200 заинтересованным сторонам, 70 из них ответили на вопросы анкеты, а 81,16% пришлось на личный кабинет, если вам интересно, вы также можете заполнить ее для меня.опрос
-
Дата сбора данных: 21.09.2021—08.10.2021
-
Целевая группа: все разработчики
-
Размер организации: Менее 50 человек, от 50 до 100 человек, более 100 человек
Выполняли ли вы модульные тесты JavaScript?
Еще один интересный вывод из опроса заключается в том, что модульное тестирование более популярно в крупных организациях. Одна из причин может заключаться в том, что крупным организациям приходится иметь дело с крупномасштабными продуктами и частыми итерациями функций. Этот непрерывный итеративный подход заставляет их инвестировать в автоматизированное тестирование. В частности, модульное тестирование помогает повысить общее качество продукта.
Кроме того, отчет показывает, что более 80% людей считают, что модульное тестирование может эффективно улучшить качество, более 60% использовали Jest для написания интерфейсных модульных тестов, и более 40% считают, что покрытие модульным тестированием важно и должно быть больше. чем 80%.
Общие инструменты модульного тестирования
Наиболее часто используемые интерфейсные фреймворки модульного тестирования:Mocha,Jest, но я рекомендую вам использовать Jest, потому что Jest имеет очевидные преимущества перед Mocha с точки зрения запуска и проблем с github и загрузок npm.
Для получения данных о звездах github и загрузках npm в реальном времени см.:jest vs mochaДата скриншота 2021.11.25
Github stars & issues
нпм-загрузки
Jest имеет большое количество загрузок, отчасти потому, что шаблон создания-реакции-приложения имеет встроенный Jest по умолчанию, и большинство проектов реагирования создаются с его помощью.
С точки зрения запуска и проблем с github и загрузок npm, Jest привлекает больше внимания и более активное сообщество.
сравнение кадров
Рамка | утверждение | асинхронный | покрытие кода |
---|---|---|---|
Mocha | Не поддерживается (требуется поддержка другой библиотеки) | дружелюбный | Не поддерживается (требуется поддержка другой библиотеки) |
Jest | Поддержка по умолчанию | дружелюбный | служба поддержки |
- Mocha имеет хорошую экологию, но требует дополнительной настройки для достижения высокой масштабируемости.
- Шутка из коробки
Например, напишите вариант использования функции суммы
./sum.js
function sum(a, b) {
return a + b;
}
module.exports = sum;
Мокко + чайный путь
Mocha необходимо импортировать chai или другую библиотеку утверждений для утверждения, если вам нужно просмотреть отчет о покрытии, вам также необходимо установить nyc или другие инструменты покрытия.
./test/sum.test.js
const { expect, assert } = require('chai');
const sum = require('../sum');
describe('sum', function() {
it('adds 1 + 2 to equal 3', () => {
assert(sum(1, 2) === 3);
});
});
Шуточный способ
Jest по умолчанию поддерживает утверждения и тесты покрытия по умолчанию.
./test/sum.test.js
const sum = require('./sum');
describe('sum function test', () => {
it('sum(1, 2) === 3', () => {
expect(sum(1, 2)).toBe(3);
});
// 这里 test 和 it 没有明显区别,it 是指: it should xxx, test 是指 test xxx
test('sum(1, 2) === 3', () => {
expect(sum(1, 2)).toBe(3);
});
})
Видно, что Jest имеет большие преимущества с точки зрения популярности и написания, поэтому рекомендуется использовать Jest «из коробки».
С чего начать?
1. Установите зависимости
npm install --save-dev jest
2. Простой пример
Сначала создайте файл sum.js
./sum.js
function sum(a, b) {
return a + b;
}
module.exports = sum;
Создайте файл с именем sum.test.js, содержащий фактическое содержимое теста:
./test/sum.test.js
const sum = require('../sum');
test('adds 1 + 2 to equal 3', () => {
expect(sum(1, 2)).toBe(3);
});
Добавьте следующий раздел конфигурации в ваш package.json
{
"scripts": {
"test": "jest"
},
}
Запустив npm run test, jest выведет следующее сообщение
3. Некоторые синтаксисы ES6 не поддерживаются
NODEJS принимает модульную спецификацию Commonjs, а также использует для импорта модулей; в то время как импорт - это модульное описание ключевое слово ES6. Если вы хотите использовать импорт, вы должны представить поддержку Babel Escape, компилируйте его через Babel и сделать его модульным кодом для узла
Если следующий файл будет перезаписан в ES6, запуск npm run test сообщит об ошибке.
./sum.js
export function sum(a, b) {
return a + b;
}
./test/sum.test.js
import { sum } from '../sum';
test('adds 1 + 2 to equal 3', () => {
expect(sum(1, 2)).toBe(3);
});
сообщить об ошибке
Чтобы использовать эти новые функции, нам нужно использовать babel для преобразования синтаксиса ES6 в ES5.
Решение
Установить зависимости
npm install --save-dev @babel/core @babel/preset-env
Добавьте .babelrc в корневой каталог
{ "presets": ["@babel/preset-env"] }
Запустите npm run test еще раз, проблема решена
принцип
Среда выполнения jest выполняет (jest-babel) внутренне, определяет, установлен ли babel-core, затем берет конфигурацию в .babelrc и объединяет babel для преобразования кода тестового примера перед запуском теста, а затем снова тестирует его.
4. Протестируйте файл ts
Jest должен использовать .babelrc для разбора файлов TypeScript перед тестированием.
Установить зависимости
npm install --save-dev @babel/preset-typescript
**Переопределить **.babelrc
{ "presets": ["@babel/preset-env", "@babel/preset-typescript"] }
Чтобы решить ошибку типа метода утверждения шутки в редакторе, такую как ошибка теста и ожидания, вам также необходимо установить
npm install --save-dev @types/jest
./get.ts
/**
* 访问嵌套对象,避免代码中出现类似 user && user.personalInfo ? user.personalInfo.name : null 的代码
*/
export function get<T>(object: any, path: Array<number | string>, defaultValue?: T) : T {
const result = path.reduce((obj, key) => obj !== undefined ? obj[key] : undefined, object);
return result !== undefined ? result : defaultValue;
}
./test/get.test.ts
import { get } from './get';
test('测试嵌套对象存在的可枚举属性 line1', () => {
expect(get({
id: 101,
email: 'jack@dev.com',
personalInfo: {
name: 'Jack',
address: {
line1: 'westwish st',
line2: 'washmasher',
city: 'wallas',
state: 'WX'
}
}
}, ['personalInfo', 'address', 'line1'])).toBe('westwish st');
});
запустить npm запустить тест
5. Непрерывный мониторинг
Чтобы повысить эффективность, jest может постоянно отслеживать изменения файлов, добавляя параметры запуска, вместо повторного выполнения тестового примера после каждой модификации.
Переписать package.json
"scripts": { "test": "jest --watchAll" },
Эффект
5. Создайте отчет о тестовом покрытии
Что такое покрытие юнит-тестами?
Покрытие модульным тестированием — это мера тестирования программного обеспечения, которая относится к доле кода, прошедшего модульное тестирование, во всех функциональных кодах. Существует множество инструментов автоматизированного тестирования, которые предоставляют эту статистику, самые основные из которых:
单元测试覆盖率 = 被测代码行数 / 参测代码总行数 * 100%
Как сгенерировать?
Присоединяйся jest.config.js
документ
module.exports = {
// 是否显示覆盖率报告
collectCoverage: true,
// 告诉 jest 哪些文件需要经过单元测试测试
collectCoverageFrom: ['get.ts', 'sum.ts', 'src/utils/**/*'],
}
снова запустить эффект
Интерпретация параметров
имя параметра | имея в виду | иллюстрировать |
---|---|---|
% stmts | Заявление о покрытии | Выполняется ли каждое выражение? |
% Branch | охват филиала | Выполняется ли каждый блок if? |
% Funcs | покрытие функций | Каждая ли функция вызывается? |
% Lines | покрытие линии | Каждая строка выполняется? |
Установите порог покрытия модульным тестом
Лично считаю, что раз уж юнит-тесты интегрированы в проект, то очень нужно обращать внимание на качество юнит-тестов, а показатель покрытия в определенной степени объективно отражает качество юнит-тестов. подскажите, установив пороговое значение модульного теста. Достиг ли пользователь ожидаемого качества.
jest.config.js
документ
module.exports = {
collectCoverage: true, // 是否显示覆盖率报告
collectCoverageFrom: ['get.ts', 'sum.ts', 'src/utils/**/*'], // 告诉 jest 哪些文件需要经过单元测试测试
coverageThreshold: {
global: {
statements: 90, // 保证每个语句都执行了
functions: 90, // 保证每个函数都调用了
branches: 90, // 保证每个 if 等分支代码都执行了
},
},
Вышеупомянутые пороговые значения требуют, чтобы наши тестовые примеры были достаточными. Если наших тестовых случаев недостаточно, следующая ошибка поможет вам улучшить
6. Как писать модульные тесты
Ниже мы возьмем метод fetchEnv в качестве примера, чтобы написать полный набор модульных тестов для справки читателей.
Напишите метод fetchEnv
./src/utils/fetchEnv.ts
документ
/**
* 环境参数枚举
*/
enum IEnvEnum {
DEV = 'dev', // 开发
TEST = 'test', // 测试
PRE = 'pre', // 预发
PROD = 'prod', // 生产
}
/**
* 根据链接获取当前环境参数
* @param {string?} url 资源链接
* @returns {IEnvEnum} 环境参数
*/
export function fetchEnv(url: string): IEnvEnum {
const envs = [IEnvEnum.DEV, IEnvEnum.TEST, IEnvEnum.PRE];
return envs.find((env) => url.includes(env)) || IEnvEnum.PROD;
}
Напишите соответствующие модульные тесты
./test/fetchEnv.test.ts
документ
import { fetchEnv } from '../src/utils/fetchEnv';
describe('fetchEnv', () => {
it ('判断是否 dev 环境', () => {
expect(fetchEnv('https://www.imooc.dev.com/')).toBe('dev');
});
it ('判断是否 test 环境', () => {
expect(fetchEnv('https://www.imooc.test.com/')).toBe('test');
});
it ('判断是否 pre 环境', () => {
expect(fetchEnv('https://www.imooc.pre.com/')).toBe('pre');
});
it ('判断是否 prod 环境', () => {
expect(fetchEnv('https://www.imooc.prod.com/')).toBe('prod');
});
it ('判断是否 prod 环境', () => {
expect(fetchEnv('https://www.imooc.com/')).toBe('prod');
});
});
Результаты
7. Общие методы утверждения
Существует много методов утверждения, здесь только самые распространенные, если вы хотите узнать больше, вы можете перейти кAPI официального сайта JestЧастичный вид
Модификатор .not позволяет проверять случаи, когда результат не равен значению.
./test/sum.test.js
import { sum } from './sum';
test('sum(2, 4) 不等于 5', () => {
expect(sum(2, 4)).not.toBe(5);
})
Сопоставитель .toEqual будет рекурсивно проверять, равны ли все атрибуты и значения атрибутов объекта, и часто используется для обнаружения ссылочных типов.
./src/utils/userInfo.js
export const getUserInfo = () => {
return {
name: 'moji',
age: 24,
}
}
./test/userInfo.test.js
import { getUserInfo } from '../src/userInfo.js';
test('getUserInfo()返回的对象深度相等', () => {
expect(getUserInfo()).toEqual(getUserInfo());
})
test('getUserInfo()返回的对象内存地址不同', () => {
expect(getUserInfo()).not.toBe(getUserInfo());
})
.toHaveLength можно легко использовать для проверки того, соответствует ли длина типов строк и массивов ожидаемым значениям.
./src/utils/getIntArray.js
export const getIntArray = (num) => {
if (!Number.isInteger(num)) {
throw Error('"getIntArray"只接受整数类型的参数');
}
return [...new Array(num).keys()];
};
./test/getIntArray.test.js
./test/getIntArray.test.js
import { getIntArray } from '../src/utils/getIntArray';
test('getIntArray(3)返回的数组长度应该为3', () => {
expect(getIntArray(3)).toHaveLength(3);
})
.toThorw позволяет нам проверить, выдает ли тестируемый метод исключение, как и ожидалось.
Одно предостережение: мы должны обернуть тестируемую функцию функцией, как это делает getIntArrayWrapFn ниже, иначе утверждение не будет выполнено, потому что функция выдает ошибку.
./test/getIntArray.test.js
import { getIntArray } from '../src/utils/getIntArray';
test('getIntArray(3.3)应该抛出错误', () => {
function getIntArrayWrapFn() {
getIntArray(3.3);
}
expect(getIntArrayWrapFn).toThrow('"getIntArray"只接受整数类型的参数');
})
.toMatch передает регулярное выражение, что позволяет нам выполнять регулярное сопоставление типов строк.
./test/userInfo.test.js
import { getUserInfo } from '../src/utils/userInfo.js';
test("getUserInfo().name 应该包含'mo'", () => {
expect(getUserInfo().name).toMatch(/mo/i);
})
Тестировать асинхронные функции
./servers/fetchUser.js
/**
* 获取用户信息
*/
export const fetchUser = () => {
return new Promise((resole) => {
setTimeout(() => {
resole({
name: 'moji',
age: 24,
})
}, 2000)
})
}
./test/fetchUser.test.js
import { fetchUser } from '../src/fetchUser';
test('fetchUser() 可以请求到一个用户名字为 moji', async () => {
const data = await fetchUser();
expect(data.name).toBe('moji')
})
Здесь вы можете увидеть такую ошибку
Это потому что@babel/preset-env
Вызвано тем, что не поддерживает асинхронное ожидание, вам необходимо улучшить конфигурацию babel, которую можно установить@babel/plugin-transform-runtime
Этот плагин решает
npm install --save-dev @babel/plugin-transform-runtime
Тем временем переписать .babelrc.
{
"presets": ["@babel/preset-env", "@babel/preset-typescript"],
"plugins": ["@babel/plugin-transform-runtime"]
}
Запустите еще раз и ошибки не будет
.toContain соответствует тому, содержит ли объект
./test/toContain.test.js
const names = ['liam', 'jim', 'bart'];
test('匹配对象是否包含', () => {
expect(names).toContain('jim');
})
Проверьте некоторые специальные значения (null, undefined и boolean)
toBeNull 仅匹配 null
toBeUndefined 仅匹配 undefined
toBeDefined 与…相反 toBeUndefined
toBeTruthy 匹配 if 语句视为 true 的任何内容
toBeFalsy 匹配 if 语句视为 false 的任何内容
检查数字类型(number)
toBeGreaterThan 大于
toBeGreaterThanOrEqual 至少(大于等于)
toBeLessThan 小于
toBeLessThanOrEqual 最多(小于等于)
toBeCloseTo 用来匹配浮点数(带小数点的相等)
Суммировать
Вышеизложенное - это все содержание статьи. Я считаю, что после прочтения этой статьи вы освоили базовые знания по интерфейсному модульному тестированию. Вы даже можете следовать обучающим шагам статьи, и теперь вы можете получить доступ к модульному тестированию в ваш проект. В то же время, если у вас возникнут какие-либо вопросы в процессе чтения или у вас появятся лучшие идеи и лучшие рекомендации по фреймворку, вы можете оставить сообщение в области комментариев!
Возможно, до того, как вы прочитали эту статью, вы освоили навыки модульного тестирования интерфейса и даже стали мастером в этой области.Прежде всего, я очень польщен, и я искренне приглашаю вас высказать свое ценное мнение в области комментариев. , Я здесь, чтобы сказать спасибо заранее!
Наконец, спасибо, что взяли эту статью в свой плотный график, дарите людям розы, есть аромат, если вы думаете, что статья вам поможет, надеюсь, я смогу помочь мне!
использованная литература
К слову о юнит-тестировании переднего плана
Рекомендуемое чтение
- Руководство по разработке плагинов для Sketch
- Почему не рекомендуется использовать индекс в качестве ключа в Vue
- Анализ технической схемы и реализация записи веб-экрана
работы с открытым исходным кодом
- Zhengcaiyun интерфейсный таблоид
адрес с открытым исходным кодомwww.zoo.team/openweekly/(На главной странице официального сайта таблоида есть группа обмена WeChat)
- Плагин выбора товара
адрес с открытым исходным кодомGitHub.com/Chinese Patent Medicine-Inc/Reservoir…
Карьера
ZooTeam, молодая, увлеченная и творческая команда, связанная с отделом исследований и разработок продукции Zhengcaiyun, базируется в живописном Ханчжоу. В настоящее время в команде более 60 фронтенд-партнеров, средний возраст которых составляет 27 лет, и почти 40% из них — инженеры полного стека, настоящая молодежная штурмовая группа. В состав членов входят «ветераны» солдат из Ali и NetEase, а также первокурсники из Чжэцзянского университета, Университета науки и технологий Китая, Университета Хандянь и других школ. В дополнение к ежедневным деловым связям, команда также проводит технические исследования и фактические боевые действия в области системы материалов, инженерной платформы, строительной платформы, производительности, облачных приложений, анализа и визуализации данных, а также продвигает и внедряет ряд внутренних технологий. Откройте для себя новые горизонты передовых технологических систем.
Если вы хотите измениться, вас забрасывают вещами, и вы надеетесь начать их бросать; если вы хотите измениться, вам сказали, что вам нужно больше идей, но вы не можете сломать игру; если вы хотите изменить , у вас есть возможность добиться этого результата, но вы не нужны; если вы хотите изменить то, чего хотите достичь, вам нужна команда для поддержки, но вам некуда вести людей; если вы хотите изменить установившийся ритм, это будет "5 лет рабочего времени и 3 года стажа работы"; если вы хотите изменить исходный Понимание хорошее, но всегда есть размытие того слоя оконной бумаги.. , Если вы верите в силу веры, верьте, что обычные люди могут достичь необыкновенных вещей, и верьте, что они могут встретить лучшего себя. Если вы хотите участвовать в процессе становления бизнеса и лично способствовать росту фронтенд-команды с глубоким пониманием бизнеса, надежной технической системой, технологиями, создающими ценность, и побочным влиянием, я думаю, что мы должны говорить. В любое время, ожидая, пока вы что-нибудь напишете, отправьте это наZooTeam@cai-inc.com