На сегодняшний день тяжело себе представить сайт, который поддерживается только на одном языке. Крупные компании желают предоставлять свой онлайн продукт для жителей всех стран, не ограничивая себя только страной существования. Это разумный подход и многим нравиться, когда в списке языков на сайте ты находишь свой родной язык. Ты с радостью его выбираешь и воспринимаешь информацию с легкостью. И тут возникает проблема - как это все тестировать(под тестированием, я понимаю автоматическое тестирование)? На первый взгляд может показаться, что чем больше языков в поддержке, тем больше будет тестовых сценариев! Но это совершенно не так! В этой статье я постараюсь внятно и доступно объяснить, как заставить Cucumber проверять все языки для приложения на Ruby on Rails!
В рельсовом приложении за интернационализацию отвечает гем Rails Internationalization (руководство к гему тут).
Для начала давайте разберемся, как работает гем: рассмотрим вьюшку какой-то страницы без локализации.
<%= content_for :page_title, “Page title” %>
<div class="editorial">
<h1>Header</h1>
<p>
body text
</p>
</div>
как мы видим, в первой строке кода у нас есть титул страницы, далее следует заголовок и текстовый блок. Если к данной вьюшке прикрутить локализацию (интернационализацию) она стала бы выглядеть следующим образом:
<%= content_for :page_title, t(“home.title”) %>
<div class="editorial">
<h1><%= t(“home.header”) %></h1>
<p>
<%= t(“home.body”) %>
</p>
</div>
Что у нас изменилось? Все текстовые величины, которые были в коде заменились на вот такие ключи t(“home.title”).
Данный ключ ведет по следующему пути ~/config/locales/ а уже в данной папке находятся файлы *.yml со всеми существующими переводами. К примеру, если на сайте две локализации (английская и французская), то внутри папки locales будет 2 файла en.yml и fr.yml
Структура файлов *.yml выглядит следующим образом:
Для английской локали en.yml
en:
home:
title: "This is a title for my web page"
header: “This is a header for my web page”
body: “This is a body for my web page”
Для французской локали fr.yml
fr:
home:
title: "C'est un titre pour ma page web"
header: “C'est un en-tête de ma page web”
body: “Il s'agit d'un corps de ma page web”
Файлов и папок внутри папки ~/config/locales/ может быть много. Хорошим примером является, если все существующие страницы будут находится в отдельных папках.
Теперь давайте рассмотрим, как написать тест для проверки страницы с локализацией.
Допустим у нас есть следующий сценарий:
Scenario: User should be able to visit guest page
When I visit guest page
And I should be stay on the guest page
Steps definitions будут выглядеть следующим образом:
And(/^I should be stay on the guest page$/) do
page.should have_content(I18n.t(“guest.title”))
page.should have_content(I18n.t(“guest.body”))
end
Все достаточно просто, при проверке контента, который мы проверяем на странице мы указываем ключи интернационализации с добавлением I18n.
Бывают случаи, когда нам необходимо в одном степсе передать переменную. К примеру нам необходимо нажать клавишу “Send”, которая находится на странице с формой отправки. Есть несколько способов решить эту задачу. Рассмотрим первый пример:
Scenario: User should be able to send application form
Given I visit form page
Then I write in form
And I press “application_form.button.send”
Steps definitions выглядят следующим образом:
And(/^I press “([^\"]*)”$/) do |key|
click_button(I18n.t(key))
end
В данном случае мы просто передали ключ, как переменную и подставили её в уже привычную нам строку I18n.t(...). Все хорошо, тест работает, проверяет для всех локалей, но беда в том, что нарушается легкость чтения теста. Заказчик, прочитав данный сценарий не сразу сможет понять, что мы там пытаемся нажать - и это огромный минус такого теста. Ведь Cucumber и был разработан для того, чтобы тесты были понятны абсолютно всем, даже тем людям, которые не знакомы с функционалом и ИТ отраслью в целом.
Выход из данной ситауации есть! Рассмотрим второй пример:
Scenario: User should be able to send application form
Given I visit form page
Then I write in form
And I press “Send”
Steps definitions выглядят следующим образом:
And(/^I press “([^\"]*)”$/) do |button|
case button
when ‘Send’
button = I18n.t('application_form.send’)
when ‘XXX’
button = I18n.t('application_form.xxx’)
end
click_button(I18n.t(button))
end
Таким образом у нас есть легко читаемый и работающий сценарий для всех локалей. Минус есть, у нас добавился блок case для перебора все кнопок, которые мы хотим нажимать, но чем-то приходится жертвовать. В Вашем праве выбирать, какой из примеров лучше подходит для Вашего случая.
Следующий шаг - запуск тестов. Если вы запустите привычным для вас способом все тесты cucumber features/scenarios то тесты будут проходить для локали, которая установлена по умолчанию. Для того, чтобы переключить язык для теста, нам необходимо добавить в файл env.rb в блок Before одну строку кода:
Before do
I18n.locale = :en
end
Таким образом, перед запуском тестов, Cucumber заходит в файл env.rb для чтения настроек и видит там блок Before и из него устанавливает локаль.
Казалось бы все легко и просто! Но, в таком случае, нам постоянно придется менять значение переменной, подставляя туда необходимый язык. Это лишний раз надо искать файл, находить нужную строчку кода и постоянно её менять. Такой вариант для нас не подходит, ведь необходимо автоматизировать ВСЕ )))
Для того, чтобы процесс замены языка при запуске тестов не был трудоемким, необходимо изменить строчку
I18n.locale = :en на
I18n.locale = ENV[‘LOCALE’]
Мы добавили глобальную переменную, в которую будем передавать локаль из командной строки, при запуске тестов.
Теперь, чтобы запустить наши тесты с необходимым языком, нам необходимо выполнить следующую команду:
cucumber features/scenarios LOCALE=en
Если же вы забудете указать переменную и запустите просто cucumber features/scenarios тесты будут проходить под локалью по умолчанию.
Все просто, легко и гибко… Наслаждайтесь тестированием с Cucumber’ом :-)
Существует мнение, например, что использование операторов ветвления в step definition - плохая практика. Я такое мнение не поддерживаю, если что. А ты что думаешь?
ОтветитьУдалитьлично я использую это не step definitions, а в классах страницы, так как юзаю Page Object Pattern
Удалить