Модульное тестирование является важной частью процесса разработки. Если вы заботитесь о состоянии приложения и качестве кода, рано или поздно вы начнете автоматизировать тесты. Мой опыт показывает, что чем раньше, тем лучше. Существует несколько подходов к модульному тестированию: `test-first` и` test-after`. По этой теме появляется много священных войн. Я бы сказал, что оба варианта работают, но «тестирование в первую очередь» или разработка на основе тестирования работает лучше для меня.
К концу дня, важно только, чтобы тесты существовали и помогли выявить ошибки регрессии. Тем не менее, разработка `test-first` помогает увидеть проблему раньше и в целом обеспечивает лучшее качество кода (что завершит священную войну).
Сегодня мы собираемся написать несколько тестов, которые охватили бы существующий класс моделей Feedback.js
. Поскольку код уже написан, мы пойдем по принципу «тест после». К счастью, код довольно прост, так что это не составит проблемы для модульного тестирования. Но прежде, давайте настроим нашу тестовую инфраструктуру.
Папки и файлы
У нас будет новая папка с именем `spec`. В папке spec у меня будут папки `models` и` views`, которые будут содержать тесты для моделей и представлений.
Тесты бегуна
Я буду использовать тестовую среду Жасмин . Это очень легко установить его, что нам нужно jasmine.js
и jasmine.css
быть размещены на соответствующих папках и настройке тестовой страницы. Тестовая страница — это простой HTML-файл, который будет отправной точкой для нашего тестирования. Если вы загрузите отдельный комплект жасмина, вы увидите SpecRunner.html
внутри. Это может быть легко адаптировано для пользовательских нужд. В головной части tests.html
нам нужно сослаться на все необходимые файлы .css и .js.
<title>Feedback form specs</title> <link rel="stylesheet" type="text/css" href="content/jasmine.css"> <script type="text/javascript" src="/scripts/libs/jquery-1.7.2.js"></script> <script type="text/javascript" src="/scripts/libs/underscore.js"></script> <script type="text/javascript" src="/scripts/libs/backbone.js"></script> <script type="text/javascript" src="/scripts/libs/jasmine.js"></script> <script type="text/javascript" src="/scripts/libs/jasmine-html.js"></script> <script type="text/javascript" src="/scripts/libs/mock-ajax.js"></script> <!-- Sources --> <script type="text/javascript" src="/scripts/src/models/Feedback.js"></script> <!-- Specs --> <script type="text/javascript" src="/scripts/spec/models/Feedback.spec.js"></script>
Тесты жасмина по существу
Тестирование с жасмином — это весело и легко. Jasmine — это фреймворк в стиле BDD, поэтому, если вы практиковали TDD с другими фреймворками, этот стиль может сначала запутаться. Давайте рассмотрим тестовый скелет Жасмин.
describe('Jasmine spec', function () { var value; beforeEach(function () { value = 1; }); it ('should fail', function () { expect(value).toBe(0); }); describe('when value is changed', function () { beforeEach(function () { value = 0; }); it ('should pass', function () { expect(value).toBe(0); }) }); });
В этом примере value
наша SUT (тестируемая система). beforeEach()
Функция — это функция установки контекста, в которой инициализируется SUT (в TDD это и порядок, и действие). it
Функция является частью утверждения. Здесь мы устанавливаем наши ожидания относительно того, в каком состоянии должно быть SUT. Обратите внимание, что beforeEach
они вложены describe
, так что вы настраиваете SUT в зависимости от случая.
Написание некоторых тестов
Единственная функциональность, которую
Feedback.js
модель содержит в настоящее время, это проверка. Давайте проверим это.
describe('Feedback.js spec', function () { var model; beforeEach(function () { model = new Feedback(); }); describe('when model is validating', function () { var errors; }); });
Это с чего-то начать. Он не делает никаких утверждений, поэтому теперь мы добавим несколько реальных случаев. В первом случае атрибуты `email` и` feedback` отсутствуют.
describe('when email and feedback fields are absent', function () { beforeEach(function () { errors = model.validate({}); }); it ('should have 2 errors', function () { expect(errors.length).toBe(2); }); it ('should have email fields as invalid', function () { expect(errors[0].name).toBe('email'); }); it ('should have feedback field as invalid', function () { expect(errors[1].name).toBe('feedback'); }); });
Возможно, что пользователь положил письмо, но забыл об обратной связи.
describe('when email is set, but feedback is absent', function () { beforeEach(function () { errors = model.validate({ email: '[email protected]'}); }); it ('should have 1 error', function () { expect(errors.length).toBe(1); }); it ('should have feedback field as invalid', function () { expect(errors[0].name).toBe('feedback'); }); it ('should have error message', function () { expect(errors[0].message).toBeDefined(); }); });
Двигаясь дальше, пользователь может оставить отзыв, но забыл про электронную почту.
describe('when feedback is set, but email is absent', function () { beforeEach(function () { errors = model.validate({ feedback: 'TDD is awesome'}); }); it ('should have 1 error', function () { expect(errors.length).toBe(1); }); it ('should have email field as invalid', function () { expect(errors[0].name).toBe('email'); }); it ('should have error message', function () { expect(errors[0].message).toBeDefined(); }); });
Отчет об испытаниях
Если вы сейчас попытаетесь запустить test.html
в браузере, у вас будет что-то подобное.
Выводы
Тестирование Backbone.Model — довольно простая вещь. Это не более чем тестирование бизнес-логики, которая может находиться внутри. Тестирование представлений немного сложнее, но мы увидим, как это сделать в следующий раз.