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

Тестирование в изоляции

Прежде чем мы углубимся в то, как тестировать в Karma, есть концепция, которую необходимо обсудить перед конкретной структурой. Такова концепция изолированного тестирования. Это делается для того, чтобы ваши модульные тесты тестировали только тот код, который вы собираетесь тестировать. Это означает издевательство над написанными вами зависимостями (можно также издеваться над сторонними зависимостями, такими как momentjs). Например, если у вас есть вспомогательная функция, которая должна записывать строку в верхнем регистре, смоделируйте ее, чтобы она всегда возвращала строку в верхнем регистре.

Таким образом, если ваша зависимость в конечном итоге сломается, ее модульные тесты будут давать сбой до тех пор, пока она не будет исправлена, но не будут давать ложный флаг для модульных тестов, которые от нее зависят. Если вы не тестируете изолированно, то это не модульный тест.

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

Один из способов выявить проблему — использовать fdescribe для выполнения одного блока describe тестов. Если он работает при использовании fdescribe, но терпит неудачу, когда не выполняется изолированно, то имеет место тестовый выпуск.

описать и это заявления

Структура модульного тестирования Karma позволяет очень и очень четко читать тесты как предложения. Кроме того, чем лучше написаны операторы describe и it, тем легче будет прочитать любые ошибки, которые могут возникнуть во время модульного теста.

Во-первых, ваши блоки describe должны описывать общую сводку набора тестов. Эти блоки describe могут быть вложенными, что дает еще больше возможностей для описания выполняемых тестов. Например, возьмем набор тестов контроллера Angular:

import MyController from './my-controller.controller.js';
describe('MyController', () => {  
    describe('.$onInit', () => {
    });
});

В случае сбоя в приведенном выше тесте он будет продолжен с MyController .$onInit в операторе ошибки. Лично я предпочитаю, чтобы блоки описания были довольно ограниченными в своих формулировках. Как правило, я выполняю вызовы функций, а затем создаю вложенный блок описания, описывающий конкретный вариант использования, как таковой:

describe('MyController', () => {  
     describe('.onSubmission', () => {
         describe(' - with invalid form data', () => {
         });
     });
});

Вам не нужно идти намного дальше с вложенными блоками описания.

Описание блоков it должно быть достаточно простым. Обычно они начинаются со слова «следует» и описывают ожидаемый результат для заданных критериев тестирования. Например:

describe('MyController', () => {  
     describe('.onSubmission', () => {
         describe(' - with invalid form data', () => {
             it('should return false when form data is invalid', () => {
                // ...
             });
         });
     });
});

Использование beforeEach для правильной настройки тестовых данных

Отличительной особенностью Karma является функция beforeEach в блоке описания. Это выполняется перед выполнением каждого теста в том порядке, в котором они описаны во вложенных блоках describe данного модульного теста.

describe('Outer Describe', () => {  
  beforeEach(() => {
    console.log('1');
  });
  describe('Inner Describe', () => {
    beforeEach(() => {
       console.log('2');
    });
    it('should not fail', () => {
       assert(true).to.be.true;
    });
  });

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

Как я обычно подхожу к этому, я использую самый внешний блок описания для создания необходимых объектов (таких как контроллер, служба и т. д.). Наиболее глубоко вложенный метод beforeEach используется для настройки правильных данных для тестовых случаев.

Использование afterEach для сброса тестового состояния

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

Кроме того, я всегда объявляю afterEach сразу после beforeEach. Таким образом, мне не нужно прокручивать сотни строк тестов, чтобы определить, что происходит после выполнения каждого теста. Кроме того, Karma не волнует, где она объявлена ​​в области блока, так что еще больше причин переместить ее вверх!