Мы разработали инструмент с открытым исходным кодом для написания технических руководств на основе Git. Все руководства в нашем сообществе Tuque написаны с использованием этого инструмента. Добро пожаловатьStarой
Если вы хотите быстро понять, как его использовать, добро пожаловать в нашУчебная документацияой
Эта статья была написана членами сообщества Tuque.sthнаписано, присоединяйтесьСообщество Туке, чтобы вместе создавать замечательные бесплатные технические руководства, чтобы способствовать развитию индустрии программирования.
Если вы считаете, что мы хорошо поработали, помнитеНравится + Подписаться + КомментарийСанлиан, поощряй нас писать лучшие уроки 💪
Когда я впервые услышал о TDD (Test-Driven Develop, разработка через тестирование), первое, о чем я подумал, это то, что дамы-испытатели хотят что-то делать? Позже я обнаружил, что эта штука пытается убить тест.Ну, давайте начнем убивать эту группу ошибок для нас весь день... Давайте начнем с простого модульного теста, чтобы начать работу с тестовой средой Jest.
Чему мы можем научиться?
- Как Jest идеально сочетается с Typescript (заполняющая запись)
- Jest’s Sharpest Features Имитация функций
Исходный код, задействованный в этой статье, размещен вGithubНа, если вы считаете, что наш текст неплох, я надеюсь, что вы можете дать его ❤️Нравится эта статья + звезда репозитория Github❤️ о
Инициализация проекта
Создать проект
# 注意powershell中'&&'替换为';'
mkdir jest-just-go && cd jest-just-go
инициализация
npm init -y
Установить зависимости
npm i jest --save-dev
1. Как Jest завершает тестовый пример с 4 строками кода
Инициализировать конфигурацию Jest по умолчанию
npx jest --init
Во время инициализации появится подсказка, нажмите y или введите.
Напишите код функции
Теперь давайте официально начнем, чай и десерты, тщательно приготовленные сообществом Tuque, еще лучше.
Создайте новый проект в корневом каталоге проектаsrc目录,存放我们的功能代码。 затем создайтеsrc/dessert.js.
const dessert = function (name) {
this.name = name;
}
dessert.prototype = {
enjoy: function () {
return "Enjoy the " + this.name;
}
}
module.exports = dessert;
Мы написали тип десерта, который имеет метод, предлагающий дегустацию.enjoy
Пишите тестовые случаи
Давайте начнем кодировать и реализовать модульный тест вышеупомянутой десертной функции.
Создайте новый проект в корневом каталоге проекта__tests__Каталог, магазин наших тест-кейсов. затем создайте__tests__/dessert.test.js.
const dessert = require("../src/dessert");
describe("test dessert feature", () => {
test("enjoy the cake", () => {
const cake = new dessert('cake');
expect(cake.enjoy()).toBe("Enjoy the cake");
})
})
describe,test,expectэти 3JestКлючевое слово на линии:
-
describetestвариант использования, вы можете добавитьbeforeEach \ afterEach、beforeAll \ afterAll(Из-за недостатка места этот тип расширенных функций будет помещен в последующие руководства) для всех следующихtestЕдиное описание и обработка. -
test: описывает конкретные тестовые случаи и является наименьшей единицей модульного тестирования. -
expect:Jestв итоге падает на каждую пару результатов тестаожидатьна, черезexpectВозвращаемое значение или результат выполнения функции сравнивается с ожидаемым значением.
выполнить тест
Вернувшись в консоль, введите:
npm test
Без дальнейшей конфигурации результаты теста показывают следующее:
в:
-
%StmtsЭто охват заявления: выполняется ли он для каждого утверждения?
-
%BranchПокрытие ветвей (покрытие ветвей): выполняется ли не каждый блок if?
-
%Funcs
%Lines
%Stmtsа также%LinesРазница в том, что степень детализации покрытия строк больше, чем покрытия операторов, потому что может быть разрешено несколько операторов в одной строке (особенно часто при разработке js).
мы меняемся__tests__/dessert.test.js:
expect(cake.enjoy()).toBe("Enjoy the cake");
改为
expect(cake.enjoy()).toBe("enjoy the cake");
Выполните тестовую команду, чтобы увидеть, не прошел ли тест:
2. Как Jest достигает 100% охвата тестами
Когда наши функциональные сценарии постепенно усложняются, наши тесты должны гарантировать, что покрытие тестовых случаев достигает стандарта. Лучше всего, конечно, 100%, чтобы маленькие тестировщики не могли найти наши ошибки, и они взяли на себя инициативу поговорить с нами, когда им нечего делать.Хорошая жизнь начинается со 100% охвата тестовых случаев .
Напишите код функции
Что делать, если не хватает десертов? Откроем магазин! Пусть сначала будет достаточно жареной красной фасоли и тирамису~
const dessert = require("./dessert");
const dessertFactory = function () {
}
dessertFactory.produce = function (type) {
switch (type) {
case 'Red bean burning':
return new dessert('Red bean burning'); // 红豆烧
case 'Tiramisu':
return new dessert('Tiramisu'); // 提拉米苏
default:
throw new Error("please choose a dessert type");
}
}
module.exports = dessertFactory;
что есть сейчасdessertFactory.produce(...)заказ в порядке~
Пишите тестовые случаи
Однако, чтобы убедиться, что мы должны иметь возможность есть, когда хотим есть (это очень важно), давайте сначала проверим:
__tests__/dessertFactory.test.js
const dessertFactoty = require("../src/dessertFactoty");
describe("test dessertFactoty feature", () => {
test("produce all dessert", () => {
const dessertType = ['Red bean burning', 'Tiramisu'];
expect(dessertFactoty.produce(dessertType[0]).enjoy()).toBe("Enjoy the Red bean burning");
})
})
-- "Я не хочу, чтобы вы думали, я хочу, чтобы я думал", я хочу полноценный "акт сдачи-приемки"!
-- Хорошо, а как насчет отображения веб-страницы?
настроитьjest.config.jsСохранить отчет о выполнении покрытия тест-кейсов
мы реализуем初始化Jest默认配置Когда он сгенерирован, он будет сгенерирован в корневом каталоге проекта.jest.config.js, в котором перечислены все элементы конфигурации, а те, которые не заданы, закомментированы. Чтобы сохранить отчет о покрытии, формируемый после каждого выполнения теста, нам нужно найти следующее свойство конфигурации и изменить его:
// Indicates whether the coverage information should be collected while executing the test
collectCoverage: true,
Тогда мы можемВыполните тестовую команду еще раз и откройте ее в браузере_/coverage/lcov-report/index.html_ Проверьте отчет о тестовом покрытии:
__tests__/dessertFactory.test.js
const dessertFactoty = require("../src/dessertFactoty");
describe("test dessertFactoty feature", () => {
test("produce all dessert", () => {
const dessertType = ['Red bean burning', 'Tiramisu'];
expect(dessertFactoty.produce(dessertType[0]).enjoy()).toBe("Enjoy the Red bean burning");
expect(dessertFactoty.produce(dessertType[1]).enjoy()).toBe("Enjoy the Tiramisu");
expect(() => { dessertFactoty.produce('Luckin Coffee') }).toThrow("please choose a dessert type");
})
})
Повторно протестируйте и посмотрите отчет о покрытии:
здесь
Functions列Почему не 100%, каждый может кликнутьdessertFactory.jsПроанализируйте предположения на основе подробного описания.3. Как Jest отлично сочетается с Typescript (заполнение пит-рекорда)
Поисковый движокJest + TypescriptПримеров относительно немного, и есть определенные проблемы, которые не были решены.Я заполнил пробел в этой части, которую можно использовать в качестве справочника по конфигурации.
увеличить зависимость
npm i ts-jest @types/jest typescript @types/node --save-dev
вts-jestдляJest + TypescriptТестирование в среде обеспечивает поддержку проверки типов и предварительную обработку.
инициализация ТС
Создайте файл конфигурации в корневом каталогеtsconfig.json:
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"lib": [
"es2015"
],
"strict": true,
"declaration": true,
"outDir": "build",
"sourceMap": true
},
"include": [
"src/**/*"
],
"exclude": [
"node_modules",
"__test__/**/*"
]
}
Исправлятьjest.config.jsнастроить
Добавьте следующие элементы конфигурации:
// An array of file extensions your modules use
moduleFileExtensions: [
"js",
"json",
"jsx",
"ts",
"tsx",
"node"
],
// A preset that is used as a base for Jest's configuration
preset: "ts-jest",
Изменить код функции
src/dessert.js => src/dessert.ts
export default class dessert {
name: string;
constructor(name: string) {
this.name = name;
}
enjoy() {
return "Enjoy the " + this.name;
}
}
src/dessertFactory.js => src/dessertFactory.ts
import dessert from "./dessert";
export default class dessertFactory {
static produce(type: string) {
switch (type) {
case 'Red bean burning':
return new dessert('Red bean burning'); // 红豆烧
case 'Tiramisu':
return new dessert('Tiramisu'); // 提拉米苏
default:
throw new Error("please choose a dessert type");
}
}
}
Изменить тестовый пример
__tests__/dessert.js => __tests__/dessert.ts
import dessert from "../src/dessert";
describe("test dessert feature", () => {
test("enjoy the cake", () => {
const cake = new dessert('cake');
expect(cake.enjoy()).toBe("Enjoy the cake");
})
})
__tests__/dessertFactory.js => __tests__/dessertFactory.ts
import dessertFactoty from "../src/dessertFactoty";
describe("test dessertFactoty feature", () => {
test("produce all dessert", () => {
const dessertType = ['Red bean burning', 'Tiramisu'];
expect(dessertFactoty.produce(dessertType[0]).enjoy()).toBe("Enjoy the Red bean burning");
expect(dessertFactoty.produce(dessertType[1]).enjoy()).toBe("Enjoy the Tiramisu");
expect(() => { dessertFactoty.produce('Luckin Coffee') }).toThrow("please choose a dessert type");
})
})
Так же, как после рефакторинга кода, мы можем быстро проверить, есть ли ошибка в изменении через тест-кейс, мы можем выполнить изменение в этот разJestПротестируйте команду, чтобы убедиться, что она не влияет на функциональность.
4. Самая острая функция Jest. Mock Functions.
оJestЧтобы протестировать функцию Mock в фреймворке, мы в основном сосредоточимся на двух моментах:
-
mock function: макет функции. -
mock return value: Высмеивать возвращаемое значение.
Из вышеизложенного можно вывести два пунктаJest
Добавлена функция комментариев к десерту:
export default class dessert {
name: string;
static comment: string[] = [];
constructor(name: string) {
this.name = name;
}
enjoy() {
return "Enjoy the " + this.name;
}
static comments(message: string) {
dessert.comment.push(message);
}
}
Интерактивная зона для обсуждения десертов. Создайтеsrc/dessertCommentModule.ts:
import dessert from "./dessert";
module dessertCommentModule {
export function comments(message: string) {
dessert.comments(message);
return dessert.comment;
}
}
export default dessertCommentModule;
начать нижеtest dessert feature with mock~ Этот раздел был протестирован, рекомендуется дополнительно изучить код, почувствоватьJest mockСекрет повсюду. Если, как и следовало ожидать, ожидаются следующие результаты, то перед вами самый красивый вид на птичье сообщество Абердина:
import dessert from "../src/dessert";
import dessertCommentModule from "../src/dessertCommentModule";
jest.mock("../src/dessertCommentModule");
describe("test dessert feature", () => {
test("enjoy the cake", () => {
const cake = new dessert('cake');
expect(cake.enjoy()).toBe("Enjoy the cake");
})
})
describe("test dessert feature with mock", () => {
test("enjoy the cake with mock function", () => {
const dessertFactoryMock = jest.fn(name => new dessert(name));
const cake = dessertFactoryMock('cake');
expect(cake.enjoy()).toBe("Enjoy the cake");
expect(dessertFactoryMock.mock.results[0].value.enjoy()).toBe("Enjoy the cake");
console.log(dessertFactoryMock.mock);
})
test("enjoy the cake with mock return value", () => {
const dessertFactoryMock = jest.fn(name => new dessert(name));
const cake = new dessert('cake');
dessertFactoryMock.mockReturnValue(cake);
const tiramisu = dessertFactoryMock('tiramisu');
expect(tiramisu.enjoy()).toBe("Enjoy the cake");
expect(tiramisu).toEqual(cake);
expect(dessertFactoryMock.mock.results[0].value).toEqual(cake);
})
test("comment the dessert with mock module", () => {
const mockedDessert = dessertCommentModule as jest.Mocked<typeof dessertCommentModule>;
mockedDessert.comments.mockReturnValue(['not bad']);
expect(mockedDessert.comments("cake is so good")).toEqual(['not bad']);
expect(dessert.comment).toEqual([]);
})
test("comment the dessert with mock implementations", () => {
const mockedDessert = dessertCommentModule as jest.Mocked<typeof dessertCommentModule>;
mockedDessert.comments.mockImplementation((message: string) => {
dessert.comments(message);
return ['not bad'];
});
expect(mockedDessert.comments("cake is so good")).toEqual(['not bad']);
expect(dessert.comment).toEqual(['cake is so good']);
})
})
mock function
Примечание: мы можем изменитьtestдляtest.onlyтолько дляtest.onlyВыполняйте тесты на тестовых примерах, сокращайте время тестирования и сосредоточьтесь на конкретных контрольных точках.
test.only("enjoy the cake with mock function", () => { ...
Здесь мы проходимjest.fnПроведенныйmock functionФункция отображения, выполнивnpm testВидеть.mock
.mockСередина будет записыватьmock function.
mock return value
test("enjoy the cake with mock return value", () => {
....
Здесь мы проходим.mockReturnValuмогуfunction mock.mockReturnValue中填充的返回值。 выполнивnpm testпроверять.
mock module
import dessertCommentModule from "../src/dessertCommentModule";
jest.mock("../src/dessertCommentModule");
test.only("comment the dessert with mock module", () => {
...
пройти черезjest.mock,НАСmockСоздайте область комментариев к десерту, эта операция может заставить насdessertCommentModuleВсе функции в нашей тестовой настройке. Здесь мы передаем функцию комментарияmock return value, выполнивnpm testВидеть:
не вошел
dessertCommentModuleсерединаcommentsметод, который напрямую возвращает предустановленное возвращаемое значение.
mock implementations
test.only("comment the dessert with mock implementations", () => {
...
Мы делаем это, комментируяmock implementations, выполнивnpm testВидеть:
попал внутрь
mockImplementationпроверить пользовательскую функцию в и вызватьdessertсерединаcommentsметод.над.
Ссылаться на
https://jestjs.io/docs/en/getting-started
https://www.valentinog.com/blog/jest
https://dev.to/muhajirdev/unit-testing-with-typescript-and-jest-2gln
Хотите узнать больше интересных практических технических руководств? ПриходитьСообщество ТукеМагазин вокруг.
Исходный код, задействованный в этой статье, размещен вGithubНа, если вы считаете, что наш текст неплох, я надеюсь, что вы можете дать его ❤️Нравится эта статья + звезда репозитория Github❤️ о