Резюме
Независимо от того, разрабатываете ли вы небольшие или большие приложения, можно с уверенностью сказать, что пользовательское тестирование является важным аспектом процесса разработки.
Но как вы тестируете надежно и непрерывно, особенно если у вас нет людей, которые могут протестировать ваше приложение каждый раз, когда оно изменяется? Естественно, программное обеспечение соответствует этим требованиям.
За эти годы разработчики создали множество приложений и технологий, чтобы удовлетворить эту потребность. Селен, который работает очень хорошо, является ярким примером. Но мы всегда ищем новые, более простые (а иногда и «круче») способы сделать то, что мы делаем. Так недавно я начал изучать новую перспективную технологию: PhantomJS .
Что такое PhantomJS?
PhantomJS — это безголовый WebKit с JavaScript API. Он имеет быструю и встроенную поддержку различных веб-стандартов: обработка DOM, селекторы CSS, JSON, Canvas и SVG.
PhantomJS был создан Арией Хидаят . Сама по себе это довольно впечатляющая технология, но, читая сайт и все сопутствующие API, я наткнулся на CasperJS .
Что такое CasperJS?
Casper — это утилита для написания сценариев и тестирования навигации для PhantomJS, написанная на JavaScript. Это позволяет нам тестировать сайты, такие как PHPUnit или JUnit, что позволяет нам тестировать наш код.
Он действительно выглядит как отличный инструмент — тот, который очень прост для запуска через JavaScript для широкого спектра моих потребностей в тестировании, и тот, который может быть очень легко интегрирован в мой текущий рабочий процесс разработки. Это выглядит как неплохое сочетание бэкэнда и фронтэнда.
В этой статье я расскажу об основах использования CasperJS. Я буду выдавать себя за обычного пользователя, опрашивающего страницу сайта New Relic, в частности, раздел « Мониторинг реальных пользователей ».
Я выбрал эту страницу, потому что она имеет множество аспектов, которые являются общими для стандартного сайта или приложения, таких как изображения, формы, кнопки, ссылки и текст. Он наполнен контентом и нам есть над чем поработать и протестировать. Теперь я уверен, что хорошие люди из New Relic уже делают это, но я также уверен, что они не будут возражать, если я настрою простой набор тестов и утверждений на сайте.
Особенности
CasperJS имеет ряд функций. В этой статье я сосредоточусь на API тестера . Он имеет ряд функций и утверждений, которые вы ожидаете от хорошего API тестирования, включая:
* assertTextExists
* assertTitle
* assertHttpStatus
* assertDoesntExist
* assertUrlMatch
Я буду использовать эти утверждения, чтобы показать, как работает CasperJS. Он также содержит ряд других функций, но я не собираюсь подробно останавливаться на них — достаточно лишь для того, чтобы сделать рабочий пример. Тем не менее, я рекомендую вам ознакомиться с отличной документацией по API . Это приятно читать, потому что это так ясно и кратко.
Требования
Если вы еще этого не сделали, установите PhantomJS или Casper, прежде чем мы продолжим работу. Теперь давайте погрузимся прямо в.
Начало работы
Когда я впервые загрузил страницу «Real User Monitoring» на сайте New Relic, она выглядела как на картинке ниже (она изменилась со времени написания этой статьи). Я выделил начальную точку формы регистрации.
Если вы щелкнете по любому элементу этой формы, остальная часть откроется так, как это показано на рисунке ниже.
Тесты будут сосредоточены на форме, но мы также рассмотрим тег заголовка, изображение в левой части формы и текст над ней.
Кодекс
Во-первых, чтобы сэкономить время, я инициализировал две переменные: одну для хранения URL-адреса и одну для имени сайта, потому что я буду использовать их в сообщениях об успешном выполнении теста.
var url = 'http://newrelic.com/product/real-user-monitoring'; var siteName = 'NewRelic';
Casper поставляется с четырьмя встроенными уровнями регистрации:
* отладка
* информация
* предупреждение
* ошибка
По умолчанию CasperJS отфильтровывает любые записи в журнале под уровнем «ошибка». Так что, если вы начинаете входить в систему и сначала ничего не видите, это может быть причиной. Чтобы убедиться, что выводится журнал, я установил для него значение «отладка». Я также отключил опцию «verbose». Если он включен, мы увидим информацию практически обо всем, что может быть довольно отвлекающим.
var casper = require('casper').create({ verbose: false, logLevel: 'debug' });
Вы можете найти другие параметры конфигурации на странице API Casper . Функция комментария, как показано ниже, позволяет нам записывать вывод — в данном случае на консоль. Я использовал простое сообщение, чтобы сказать, что тестирование началось.
casper.test.comment('Starting Testing');
Функция «casper.start» начинает запуск тестов.
casper.start(url, function() { this.test.assert( this.getCurrentUrl() === url, 'url is the one expected' ); this.test.assertHttpStatus(200, siteName + ' is up');
Вот что я сделал: я загрузил URL, который был указан в ‘url’, и заявил, что мы можем загрузить нужный адрес. После успешной загрузки страницы пришло время начать вызывать некоторые утверждения, чтобы удостовериться, что контент, который загружается на странице, соответствует нашим ожиданиям.
В этом случае я быстро проверил возвращенный код состояния, который должен быть 200, и я также получил 200. Давайте сделаем еще одно утверждение:
this.test.assertTitle( 'Real User Monitoring, End User Experience Monitoring : New Relic', siteName + ' has the correct title' );
Приведенный выше тест довольно прост. Он утверждает, что заголовок загруженной страницы является таким, каким он должен быть, а затем выводит сообщение с этой информацией.
В приведенном ниже коде я сначала проверяю, существует ли форма с идентификатором nr-signup-form. Немного бессмысленно проверять элементы формы, если форма не существует, верно?
this.test.assertExists( 'form[id="nr-signup-form"]', siteName + ' has a form with name "nr-signup-form"' );
Теперь, прежде чем идти дальше, я должен упомянуть, что когда я утверждаю, существуют ли элементы на загруженной странице, я могу использовать два разных подхода:
* XPath
* Селекторы CSS
Если вам нужна дополнительная информация о XPath, посмотрите некоторые ссылки в разделе «Дальнейшее чтение» или прочитайте этот пост, который я написал для него . Селекторы CSS должны быть довольно понятными. Но на всякий случай я также включил ссылки в раздел «Дальнейшее чтение».
Теперь давайте использовать утверждения для поиска полей ввода.
this.test.assertExists( {type: 'xpath', path: '//input[@id="FullName"]' }, 'the element exists' ); this.test.assertExists( {type: 'xpath', path: '//input[@id="Company"]' }, 'the element exists' ); this.test.assertExists( {type: 'xpath', path: '//input[@id="Email"]' }, 'the element exists' ); this.test.assertExists( {type: 'xpath', path: '//input[@id="Password"]' }, 'the element exists' ); this.test.assertExists( {type: 'xpath', path: '//input[@id="PromoCode"]' }, 'the element exists' );
В пяти утверждениях выше я искал пять полей ввода с идентификаторами «FullName», «Company», «Email», «Password» и «PromoCode». С XPath так же легко найти выбранные элементы.
В тестах, приведенных ниже, я утверждал, что есть четыре списка выбора с соответствующими идентификаторами: «страна», «группа», «company_size» и «HostEstimate».
this.test.assertExists( {type: 'xpath', path: '//select[@id="country"]' }, 'the element exists' ); this.test.assertExists( {type: 'xpath', path: '//select[@id="group"]' }, 'the element exists' ); this.test.assertExists( {type: 'xpath', path: '//select[@id="company_size"]' }, 'the element exists' ); this.test.assertExists( {type: 'xpath', path: '//select[@id="HostEstimate"]' }, 'the element exists' );
Теперь эти тесты были довольно просты. Итак, давайте сделаем их немного сложнее.
this.test.assertExists( { type: 'xpath', path: '//button[@id="sign-up-button" and @class="small-button" and @type="submit"]' }, 'the element exists' );
В приведенном выше тесте я искал кнопку «Создать бесплатную учетную запись», как показано на рисунке ниже.
Я использовал некоторые условные операторы в этом запросе. Мы ищем кнопку с:
* Идентификатор «кнопки регистрации»
* Класс «маленькой кнопки»
* Тип «отправки»
Может показаться, что я больше сосредоточен на XPath, чем на CasperJS, но потерпите немного больше для некоторых дополнительных функций и конфигурации.
var x = require('casper').selectXPath; var checkboxXpath = "//input[@type='checkbox' and @id='checkbox1']/parent::*/a/label[ contains(., 'Java') or contains(., 'Python') or contains(., 'Ruby') or contains(., 'PHP') or contains(., '.NET') or contains(., 'Node.js') ]"; this.test.assertExists(x(checkboxXpath), 'the element exists');
В этом тесте я немного упростил тест XPath, инициализировав x с помощью помощника selectXPath. Я посмотрел все флажки на этой странице с выбором «Приложения». Таким образом, запрос XPath искал флажки с сопровождающим тегом метки, который соответствует названиям языков приложения.
Просто чтобы показать, что я не использую исключительно XPath (хотя он невероятно мощный и простой), два теста ниже также используют селекторы CSS, чтобы проверить, что поле ввода и элемент списка также существуют.
this.test.assertVisible('input#Company'); this.test.assertExists('li.nav-enterprise', 'the element exists');
Легко искать элементы формы и элементы списка, но что делать, если ваша страница загружена ресурсами, с множеством изображений или объектов Flash? Вот пример:
this.test.assertResourceExists( '/images/tshirt-dude-form.png', 'T-shirt Image exists' );
С помощью теста выше я утверждал, что изображение мужчины в рекламируемой футболке загружено. В одном последнем тесте утверждается, что существует некоторый текст, в данном случае это «Зарегистрируйтесь бесплатно!» текст над снимком мужчины в футболке:
this.test.assertTextExists( 'Sign up for free!', 'page body contains "Sign up for free!"' ); });
Затем мы закрываем функцию «старт».
casper.test.comment('Ending Testing');
Тесты почти завершены, поэтому я выведу еще одну запись в журнале, чтобы пользователь знал об этом.
casper.run(function() { this.test.done(16); this.echo('So the whole suite ended.'); require('utils').dump(casper.test.getFailures()); require('utils').dump(casper.test.getPasses()); this.exit(); });
Я мог бы написать все тесты, которые я хочу, но без вызова ‘run’ ничего не произойдет. Таким образом, «запустить» запускает вышеупомянутую работу. Что я сделал, так это проверил, что скрипт выполнил 16 тестов, а затем вывел окончательную строку текста в конце с помощью this.echo ().
Когда мы запускаем тесты, иногда полезно получить сводку результатов в конце. С помощью функций getFailures () и getPasses () мы можем увидеть сводку пройденных и неудачных тестов. После всего этого я вызвал this.exit (). Это приводит к выходу из CasperJS и PhantomJS, при желании можно указать код выхода.
Сделав еще один шаг вперед, на этот раз я называю «casperjs» немного по-другому: я прохожу «тест», как показано ниже, вместе с переключателем «xunit». Это экспортирует результаты теста в XML-файл XUnit .
$ casperjs test mytest.js --xunit=log.xml
В следующей основной версии CasperJS вы не сможете запускать и отображать тесты, если «test» не будет передан команде. Важно знать это заранее и избегать неожиданного взлома ваших скриптов.
Автоматизация тестирования
Что делать, если вы хотите автоматизировать процесс тестирования? Я имею в виду, это здорово, что мы можем отрабатывать некоторые тесты вручную, но это может быть утомительным и довольно трудоемким. К счастью, есть расширение, которое помогает автоматизировать ваши тесты. Я не знал об этом, когда начал писать эту серию. Я хочу поблагодарить @casperjs_org за то, что сообщили мне о расширении resurectio для Google Chrome.
Клонируйте или загрузите копию и установите ее, затем снова откройте ту же страницу «Новая реликвия», которую мы использовали ранее, и нажмите кнопку «resurectio» в списке кнопок расширения.
На странице, где вы хотите создать автоматизированный тест, нажмите «Перейти» в поле URL страницы. Все, что вы делаете с этого момента, будет включено в состав созданного тестового сценария.
Я перебрал все элементы формы, от «Электронная почта» до «Размер компании». Затем я снова нажал кнопку расширения, чтобы остановить запись, и нажал «Экспорт CasperJS». Это открывает другую страницу в браузере, которая отображает сгенерированный скрипт.
Скопируйте это в скрипт и запустите его, как и предыдущий скрипт, который вы создали, и вы получите результат, как показано на скриншоте ниже.
Как видите, он проделал отличную работу по настройке среды и созданию всех тестовых утверждений, поэтому все, что нам нужно сделать, — это запустить его. Это позволяет легко подготовить тесты к использованию с CasperJS.
Дальнейшее чтение
* XPath
* Селекторы CSS
* CasperJS
* PhantomJS
* JUnit
* PHPUNit
Conclusion
I hope you’ve enjoyed this gentle introduction to CasperJS and appreciate the power and flexibility that it gives us to design thorough user-accepted test suites through PhantomJS.
We saw how — with a minimal amount of effort — we could test the content of the New Relic ‘Real User Monitoring’ page, albeit with some manual effort to determine the required XPath expressions and CSS selectors.
But for a free solution, it sure delivers a lot of capacity. I’m sure you’ll agree. So what did you think of it? Can you see yourself or your organization incorporating it as part of your deployment and/or continuous integration solution?
In the next part, I’ll branch out from testing and looking at other parts of the CasperJS, including:
* HTTP authentication
* Mouse events
* Submitting forms
* Impersonating user agents
* Making AJAX requests