DevGang
Авторизоваться

Рекомендации по модульному тестированию JavaScript 

Модульные тесты очень полезны для проверки работы нашего приложения.

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

В этой статье мы рассмотрим некоторые передовые практики, которым следует следовать при написании модульных тестов в JavaScript.

Дизайн для бережливого тестирования

Код теста должен быть простым, коротким и свободным от абстракций.

Они тоже должны быть поджарыми.

Чем меньше сложность у нашего тестового кода, тем он лучше.

Мы просто что-то делаем и проверяем результаты в наших тестах.

Включите 3 части в каждое название теста

У нас должно быть 3 части в каждом имени теста.

Первая часть - это тестируемый модуль.

Второе - это обстоятельство, при котором мы тестируем код.

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

Таким образом, мы можем узнать, что тестируется, и выяснить, что исправить в случае сбоя.

Например, мы пишем:

describe('User Service', function() {
  describe('Add new user', function() {
    it('When no password is specified, then the product status is pending', ()=> {
      const user = new UserService().add(...);
      expect(user.status).to.equal('pending');
    });
  });
});

Структурные тесты по шаблону AAA

Мы должны структурировать наши тесты по шаблону AAA.

3A означают Arrange, Act и Assert (аранжировку, действие и утверждение).

Arrange - означает, что код настройки добавлен, чтобы мы могли провести тест.

Act - делает тест.

Assert - проверяет результат после выполнения того, что у нас есть.

Итак, если у нас есть:

describe('User Service', function() {
  describe('login', function() {
    it('if the password is wrong, then we cannot log in', () => {
      const user = new UserService().add({ username: 'james', password: '123456' });
      const result = login('james', '123'); 
      expect(result).to.equal(false);
    });
  });
});

Согласовываем с первой строчкой теста.

Действие - это вызов функции login.

Утверждение - это вызов expect.

Опишите ожидания на языке продукта

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

Следует описать поведение, чтобы мы могли понять, что делает тест.

Символ expect или should должен быть доступен для чтения людям.

Например, мы пишем:

describe('User Service', function() {
  describe('Add new user', function() {
    it('When no password is specified, then the product status is pending', ()=> {
      const user = new UserService().add(...);
      expect(user.status).to.equal('pending');
    });
  });
});

Строки мы передаем в describe и it объясняя сценарии и тесты ясно.

Только тестовые общедоступные методы

Мы должны тестировать только общедоступные методы, чтобы не тестировать реализацию.

Нас не волнует реализация наших тестов.

Все, о чем мы заботимся, - это результаты.

Мы должны смотреть на них, когда мы не получаем ожидаемых результатов от тестов.

Это называется поведенческим тестированием.

Мы тестируем поведение и ничего больше.

Например, мы не должны писать такой код:

it('should add a user to database', () => {
  userManager.updateUser('james', 'password');

  expect(userManager._users[0].name).toBe('james');
  expect(userManager._users[0].password).toBe('password');
});

Мы не должны тестировать частные переменные, которые могут измениться в любое время.

Избегайте издевательств в пользу заглушек и шпионов

Нам нужно избавиться от некоторых зависимостей, поскольку мы не можем делать все в наших тестах, как в реальной среде.

Наши тесты не должны зависеть от чего-либо извне и должны быть изолированы.

Поэтому мы заглушаем все зависимости, которые вызывают побочные эффекты, чтобы мы могли просто протестировать то, что мы хотим протестировать изолированно.

Мы просто заглушаем любой код сетевого запроса.

И мы смотрим, что мы хотим проверить, называется шпионами.

Например, вместо издевательства над базой данных вроде:

it("should delete user", async () => {
  //...
  const dataAccessMock = sinon.mock(DAL);
  dataAccessMock
    .expects("deleteUser")
    .once()
    .withArgs(DBConfig, user, true, false);
  new UserService().delete(user);
  dataAccessMock.verify();
});

Мы следим за функцией, которую мы проверяем, написав:

it("should delete user", async () => {
  const spy = sinon.spy(Emailer.prototype, "sendEmail");
  new UserService().delete(user);
  expect(spy.calledOnce).to.be.true;
});

Мы проследили за методом sendEmail конструктора Emailer, чтобы проверить, вызывается ли он после вызова метода delete экземпляра UserService.

Мы избегаем имитации любых взаимодействий на стороне сервера с помощью шпионского подхода.

Источник:

#JavaScript
Комментарии
Чтобы оставить комментарий, необходимо авторизоваться

Присоединяйся в тусовку

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

Попробовать

Оплатив хостинг 25$ в подарок вы получите 100$ на счет

Получить