Только написав тесты, вы сможете понять значение тестирования. Насколько я знаю, никакие учебные курсы или курсы по кодированию не учат писать тесты. Написание тестов может не понадобиться для демонстрационных проектов или курсовых работ, но это необходимо для реальных приложений. Итак, в этом Часть 3 из серии «Давайте создадим и развернем веб-приложение MERN с полным стеком» я продемонстрирую, как писать тесты для компонентов ReactJs и RESTAPI ExpressJs.


Давайте начнем


Что такое тестирование?

На этапе тестирования разработки программного обеспечения фактические результаты приложения сравниваются с ожидаемыми. Этот этап используется перед развертыванием приложения, чтобы убедиться, что все работает должным образом. Начинающие разработчики часто считают, что написание тестов — это трудоемкий и неважный процесс. Но они игнорируют тот факт, что тестирование на самом деле дает вам много времени в долгосрочной перспективе. Вы можете думать о тестировании как о единовременной инвестиции.

При разработке программного обеспечения используются различные методы тестирования, включая модульное тестирование, интеграционное тестирование, бета-тестирование, регрессионное тестирование и другие. мы узнаем о Модульное тестирование в этом уроке и как создавать тесты для приложений, созданных с помощью ReactJ и NodeJ.


Что такое модульное тестирование?

Как следует из названия, модульное тестирование включает тестирование отдельных фрагментов кода или приложения. Например, в REST API мы можем создавать отдельные тесты для каждой конечной точки, а в приложении ReactJs мы можем тестировать каждый компонент отдельно.

Приступим к созданию тестов для нашего приложения «Productivity Tracker». (Если вы не знаете, что это такое, читайте предыдущую статью — Добавление аутентификации в полнофункциональное веб-приложение MERN)


Написание тестов в приложении NodeJs с помощью Jest и SuperTest

Примечание. Я рекомендую настроить отдельную базу данных для целей тестирования. Но для этого урока это не обязательно.


Шаг 1. Разделите приложение и сервер

Во-первых, нам нужно отделить сервер от приложения, потому что мы используем SuperTest для тестирования приложения, а не сервера.

Итак, создайте app.js файл в корне и вставьте этот код.

const express = require("express");
const cors = require("cors");

const ActivityRouter = require("./routes/activity.route");
const AuthRouter = require("./routes/auth.route");

const app = express();

/* Telling the application to use the express.json() middleware. This middleware will parse the body of
any request that has a Content-Type of application/json. */
app.use(express.json());

/* Allowing the frontend to access the backend. */
app.use(cors());

/* This is a route handler. It is listening for a GET request to the root route of the application.
When it receives a request, it will send back a response with the string "Hello World!". */
app.get("/", (req, res) => {
  res.send("Hello World!");
});

/* Telling the application to use the ActivityRouter for any requests that start with "/api". */
app.use("/api", ActivityRouter);

/* Telling the application to use the AuthRouter for any requests that start with "/api/auth". */
app.use("/api/auth", AuthRouter);

module.exports = app;
Войти в полноэкранный режим

Выйти из полноэкранного режима

… И в server.js.

const express = require("express");
const mongoose = require("mongoose");

const app = express();

/* Loading the environment variables from the .env file. */
require("dotenv").config();

const PORT = process.env.PORT || 5000;
const MONGODB_URI = process.env.MONGODB_URI || "mongodb://localhost/todoapiDB";

/* Connecting to the database and then starting the server. */
mongoose
  .connect(MONGODB_URI, { useNewUrlParser: true })
  .then(() => {
    app.listen(PORT, console.log("Server stated on port 5000"));
  })
  .catch((err) => {
    console.log(err);
  });
Войти в полноэкранный режим

Выйти из полноэкранного режима


Шаг 2. Установите пакеты

Чтобы начать писать тесты, вам понадобятся три пакета npm: jest, supertestа также cross-env.

npm i --save-dev jest supertest cross-env
Войти в полноэкранный режим

Выйти из полноэкранного режима

является: Jest — это фреймворк для тестирования кода JavaScript. Модульное тестирование является его основным использованием.
супертест: Используя Supertest, мы можем тестировать конечные точки и маршруты на HTTP-серверах.
перекрестная оболочка: вы можете установить переменные среды внутри команды, используя cross-env.


Шаг 3: Добавьте тестовый скрипт

Откройте свой package.json файл и добавьте тестовый скрипт в файл scripts.

"scripts": {
    "test": "cross-env NODE_ENV=test jest --testTimeout=5000",
    "start": "node server.js",
    "dev": "nodemon server.js"
},
Войти в полноэкранный режим

Выйти из полноэкранного режима

В таком случае, testTimeout установлен на 5000 потому что некоторые запросы могут занять некоторое время, и cross-env используется для установки переменных среды и jest для запуска тестовых наборов.


Шаг 4: Начните писать тесты

Сначала создайте папку с именем tests/ в корне приложения, а затем создайте там файл с именем activity.test.js. Jest ищет папку tests/ в корне проекта, когда вы делаете npm run test. В результате вы должны поместить свои тестовые файлы в tests/ папка.

Далее импортируйте supertest а также mongoose пакеты в тестовый файл.

const mongoose = require("mongoose");
const request = require("supertest");
Войти в полноэкранный режим

Выйти из полноэкранного режима

импорт dotenv для загрузки переменных среды и импорта app.js так как именно здесь начинается наше приложение.

const mongoose = require("mongoose");
const request = require("supertest");

const app = require("../app");

require("dotenv").config();
Войти в полноэкранный режим

Выйти из полноэкранного режима

Вам нужно будет подключать и отключать базу данных до и после каждого теста (поскольку нам не требуется база данных после завершения тестирования).

/* Connecting to the database before each test. */
beforeEach(async () => {
  await mongoose.connect(process.env.MONGODB_URI);
});

/* Closing database connection after each test. */
afterEach(async () => {
  await mongoose.connection.close();
});
Войти в полноэкранный режим

Выйти из полноэкранного режима

Теперь напишите свой первый модульный тест.

describe("GET /api/activities", () => {
  it("should get all the activities", async () => {
    const token = await request(app).post("/api/auth/login").send({
      email: process.env.EMAIL,
      password: process.env.PASSWORD,
    });

    const response = await request(app)
      .get("/api/activities")
      .set({
        Authorization: "bearer " + token.body.token,
        "Content-Type": "application/json",
      });

    expect(response.statusCode).toBe(200);
    expect(response.body.length).toBeGreaterThan(0);
  });
});
Войти в полноэкранный режим

Выйти из полноэкранного режима

В приведенном выше коде

  • Мы используем describe для описания модульного теста. Хотя это и не требуется, будет полезно идентифицировать тесты в результатах тестов.
  • В it, мы пишем фактический тестовый код. Запишите ожидаемый результат в первый аргумент, а затем во второй аргумент напишите функцию обратного вызова, содержащую тестовый код.
  • В функции обратного вызова запрос сначала отправляется в конечную точку, а затем сравниваются ожидаемый и фактический ответы. Тест считается пройденным, если оба ответа совпадают, в противном случае он не проходит.

Примечание. Поскольку в нашем приложении есть аутентифицированные маршруты, нам нужно получить токен, войдя в приложение и используя этот токен для доступа к маршруту.

Вы можете написать тесты для всех конечных точек таким же образом.

describe("POST /api/activity", () => {
  it("should add an activity to the database", async () => {
    const token = await request(app).post("/api/auth/login").send({
      email: process.env.EMAIL,
      password: process.env.PASSWORD,
    });

    const response = await request(app)
      .post("/api/activity")
      .send({
        name: "Jogging",
        time: "3:00 PM",
      })
      .set({
        Authorization: "bearer " + token.body.token,
        "Content-Type": "application/json",
      });

    expect(response.statusCode).toBe(201);
  });
});
Войти в полноэкранный режим

Выйти из полноэкранного режима

Затем запустите npm run test для запуска тестовых наборов (suite — тестовый файл).

результаты теста


Написание тестов в приложении ReactJs с библиотекой тестирования React

Точно так же напишем тесты для React-приложений. Для этого мы будем использовать Библиотека тестирования React.

@testing-library семейство пакетов помогает тестировать компоненты пользовательского интерфейса ориентированным на пользователя способом.


Шаг 1. Установите пакеты

Чтобы начать писать тесты в React, вам понадобится React Testing Library. Но эти пакеты поставляются с предустановленными создать-реагировать-приложение (КРА). Если вы не использовали CRA, вы можете установить их следующим образом.

npm install --save-dev @testing-library/react @testing-library/jest-dom @testing-library/user-event
Войти в полноэкранный режим

Выйти из полноэкранного режима


Шаг 2: Создайте тестовые файлы

Рекомендуется создать тестовый файл для каждого компонента.

У нас есть 2 компонента, которые нужно протестировать: <App /> а также <Login />. Так создайте App.test.js а также Login.test.js в src/ папка. Но пока создайте только App.test.js файл.


Шаг 3: Начните писать тесты

Напишите свой первый тест.

в App.jsx файл добавить data-testid={"app-header-heading"} атрибут основного элемента заголовка. Позже, при написании тестов, мы можем обращаться к этому элементу с этим идентификатором.

<h1 data-testid="app-header-heading">Productivity Tracker</h1>
Войти в полноэкранный режим

Выйти из полноэкранного режима

Теперь откройте App.test.js файл и вставьте приведенный ниже код.

import { render, screen } from "@testing-library/react";

import App from "./App";

/* This is a test that is testing the App component. 
 * It is testing that the heading is correct. */
describe("App", () => {
  it("should have exact heading", () => {
    /* Rendering the App component. */
    render(<App />);

    /* Getting the element with the test id of "app-header-heading". */
    const mainHeading = screen.getByTestId("app-header-heading");

    /* Checking that the innerHTML of the element with the test id of "app-header-heading" is equal to
    "Productivity Tracker". */
    expect(mainHeading.innerHTML).toBe("Productivity Tracker");
  });
});
Войти в полноэкранный режим

Выйти из полноэкранного режима

В приведенном выше коде

  • Сначала мы импортировали необходимые пакеты — render а также screen из @testing-library/react а затем импортировал компонент, который необходимо протестировать.
  • Для описания юнит-теста мы используем тот же синтаксис, что и в экспрессе. Большинство разработчиков React по соглашению помещают имя компонента в первый аргумент. Фактический тест написан как функция обратного вызова во втором аргументе.
  • В it, мы пишем фактический тестовый код. Запишите ожидаемый результат в первый аргумент, а затем во второй аргумент напишите функцию обратного вызова, содержащую тестовый код.
  • Остальной код говорит сам за себя, и вы также можете понять его из комментариев. Мы ожидаем, что компонент приложения должен содержать заголовок «Отслеживание производительности».

Это общий процесс написания теста для компонента React:

  • Визуализируйте компонент -> Напишите элементы, с которыми вы хотите взаимодействовать -> Взаимодействуйте с этими элементами -> Утвердите, что результаты соответствуют ожиданиям.

Теперь запустите npm test команда. Вы увидите результаты.

Результаты тестирования компонента приложения

Пожалуйста, обратитесь к официальной документации, чтобы узнать больше о библиотеке тестирования React и написать свои собственные тесты.


В качестве испытания попробуйте реализовать поток «Добавить активность».
В следующей статье мы узнаем кое-что о DevOps.


Также читайте,

Не стесняйтесь задавать свои сомнения в комментариях.


Понравилось читать это? Следите за новостями.