Приемочное тестирование используется для определения соответствия требованиям спецификации. Он должен работать в среде, максимально похожей на рабочую. Поэтому, если ваше приложение развернуто в Openshift, вам потребуется параллельная учетная запись с той, которая используется в рабочей среде для запуска тестов. В этом посте мы собираемся написать приемочный тест для приложения, развернутого в Openshift, которое использует MongoDb в качестве базы данных.
Развернутое приложение представляет собой простую библиотеку, которая возвращает все книги, доступные для кредитования. Это приложение использует
MongoDb для хранения всей информации, связанной с книгами.
Итак, давайте начнем с описания цели, функции, пользовательской истории и критериев приемлемости для предыдущих приложений.
Учитывая, что я хочу взять книгу
Когда я нахожусь на странице каталога
Тогда я должен увидеть информацию о доступных книгах: Властелин банок — 1299 — LOTRCoverUrl, Хоббит — 293 — HobbitCoverUrl
Обратите внимание, что это очень простое приложение, поэтому критерии принятия тоже просты.
Для этого примера нам понадобятся две тестовые среды: первая для написания и запуска приемочных тестов, а другая для управления
бэкэндом NoSQL . В этом посте мы собираемся использовать
Thucydides для
ATDD и
NoSQLUnit для работы с
MongoDb .
Приложение уже развернуто в
Openshift , и вы можете взглянуть на
https://books-lordofthejars.rhcloud.com/GetAllBooks
Thucydides — это инструмент, разработанный для облегчения написания автоматизированных приемочных и регрессионных тестов.
API WebDriver для доступа к
элементам HTML- страницы. Но это также помогает вам организовать ваши тесты и пользовательские истории с помощью конкретной модели программирования, создавать отчеты о выполненных тестах и, наконец, также измерять функциональное покрытие.
Чтобы написать приемочные тесты с
Thucydides следующие шаги должны быть выполнены.
- Прежде всего, выберите пользовательскую историю одной из ваших функций.
- Затем реализуйте класс PageObject . PageObject — это шаблон, который моделирует элементы пользовательского интерфейса веб-приложения как объекты, поэтому тесты могут взаимодействовать с ними программно. Обратите внимание, что в этом случае мы кодируем «как» мы получаем доступ к HTML- странице.
- Следующим шагом является реализация библиотеки шагов. Этот класс будет содержать все шаги, необходимые для выполнения действия. Например, для создания новой книги необходимо открыть страницу addnewbook , вставить новые данные и нажать кнопку «Отправить». В этом случае мы кодируем «что» нам нужно для реализации критериев приемлемости.
- И, наконец, кодирование выбранной пользовательской истории в соответствии с определенными критериями принятия и использованием предыдущих классов шагов.
расширение JUnit, которое нацелено на управление жизненным циклом необходимого
движка NoSQL , помогает нам поддерживать базу данных в известном состоянии и стандартизировать способ написания тестов для
приложений NoSQL .
NoSQLUnit состоит из двух групп
правил JUnit и двух аннотаций. В текущем случае нам не нужно управлять жизненным циклом
движка NoSQL , потому что он управляется внешним объектом (
Openshift ).
Итак, давайте приступим к работе:
первое, что мы собираемся сделать, это создать класс объектов, который не содержит тестовый код; он используется как способ представления структуры требований.
public class Application {
@Feature
public class Books {
public class ListAllBooks {}
}
}
Обратите внимание, что каждая реализованная функция должна содержаться в классе с
аннотацией @Feature . Каждый метод избранного класса представляет пользовательскую историю.
Следующим шагом является создание класса PageObject. Помните, что шаблон PageObject моделирует пользовательский интерфейс веб-приложения как объект. Итак, давайте посмотрим
html- файл, чтобы проверить, какие элементы должны отображаться.
<table id="listBooks" cellspacing="0" cellpadding="5">
<caption>List of Available Books</caption>
<tr>
<th>Title</th>
<th>Number Of Pages</th>
<th>Cover</th>
</tr>
.....
</table>
Самое главное здесь в том , что
таблица теги имеют
идентификаторы имени
listBooks , которые будут использоваться в классе PageObject , чтобы получить ссылку на его параметры и данные. Давайте напишем объект страницы:
@DefaultUrl("http://books-lordofthejars.rhcloud.com/GetAllBooks")
public class FindAllBooksPage extends PageObject {
@FindBy(id = "listBooks")
private WebElement tableBooks;
public FindAllBooksPage(WebDriver driver) {
super(driver);
}
public TableWebElement getBooksTable() {
Map<String, List<String>> tableValues = new HashMap<String, List<String>>();
tableValues.put("titles", titles());
tableValues.put("numberOfPages", numberOfPages());
tableValues.put("covers", coversUrl());
return new TableWebElement(tableValues);
}
private List<String> titles() {
List<WebElement> namesWebElement = tableBooks.findElements(By.className("title"));
return with(namesWebElement).convert(toStringValue());
}
private List<String> numberOfPages() {
List<WebElement> numberOfPagesWebElement = tableBooks.findElements(By.className("numberOfPages"));
return with(numberOfPagesWebElement).convert(toStringValue());
}
private List<String> coversUrl() {
List<WebElement> coverUrlWebElement = tableBooks.findElements(By.className("cover"));
return with(coverUrlWebElement).convert(toImageUrl());
}
private Converter<WebElement, String> toImageUrl() {
return new Converter<WebElement, String>() {
@Override
public String convert(WebElement from) {
WebElement imgTag = from.findElement(By.tagName("img"));
return imgTag.getAttribute("src");
}
};
}
private Converter<WebElement, String> toStringValue() {
return new Converter<WebElement, String>() {
@Override
public String convert(WebElement from) {
return from.getText();
}
};
}
}
Используя
@DefaultUrl, мы устанавливаем, какой URL отображается, с помощью
@FindBy мы отображаем веб-элемент с помощью id
listBooks и, наконец,
метод getBooksTable (), который возвращает содержимое сгенерированной
HTML- таблицы.
Следующее, что нужно сделать, это реализовать класс steps; в этом простом случае нам нужно всего два шага: первый, который открывает
страницу GetAllBooks , и другой, который утверждает, что таблица содержит ожидаемые элементы.
public class EndUserSteps extends ScenarioSteps {
public EndUserSteps(Pages pages) {
super(pages);
}
private static final long serialVersionUID = 1L;
@Step
public void should_obtain_all_inserted_books() {
TableWebElement booksTable = onFindAllBooksPage().getBooksTable();
List<String> titles = booksTable.getColumn("titles");
assertThat(titles, hasItems("The Lord Of The Rings", "The Hobbit"));
List<String> numberOfPages = booksTable.getColumn("numberOfPages");
assertThat(numberOfPages, hasItems("1299", "293"));
List<String> covers = booksTable.getColumn("covers");
assertThat(covers, hasItems("http://upload.wikimedia.org/wikipedia/en/6/62/Jrrt_lotr_cover_design.jpg", "http://upload.wikimedia.org/wikipedia/en/4/4a/TheHobbit_FirstEdition.jpg"));
}
@Step
public void open_find_all_page() {
onFindAllBooksPage().open();
}
private FindAllBooksPage onFindAllBooksPage() {
return getPages().currentPageAt(FindAllBooksPage.class);
}
}
И, наконец, класс для проверки критериев приемлемости:
@Story(Application.Books.ListAllBooks.class)
@RunWith(ThucydidesRunner.class)
public class FindBooksStory {
private final MongoDbConfiguration mongoDbConfiguration = mongoDb()
.host("127.0.0.1").databaseName("books")
.username(MongoDbConstants.USERNAME)
.password(MongoDbConstants.PASSWORD).build();
@Rule
public final MongoDbRule mongoDbRule = newMongoDbRule().configure(
mongoDbConfiguration).build();
@Managed(uniqueSession = true)
public WebDriver webdriver;
@ManagedPages(defaultUrl = "http://books-lordofthejars.rhcloud.com")
public Pages pages;
@Steps
public EndUserSteps endUserSteps;
@Test
@UsingDataSet(locations = "books.json", loadStrategy = LoadStrategyEnum.CLEAN_INSERT)
public void finding_all_books_should_return_all_available_books() {
endUserSteps.open_find_all_page();
endUserSteps.should_obtain_all_inserted_books();
}
}
Есть несколько вещей, которые следует рассмотреть в предыдущем классе:
- @Story должен получить класс, определенный с помощью аннотации @Feature , чтобы Thucydides мог правильно создать отчет.
- Мы используем MongoDbRule для установления соединения с удаленным экземпляром MongoDb . Обратите внимание, что мы можем использовать адрес localhost из-за возможности переадресации портов Openshift , поэтому, хотя localhost используется, мы действительно управляем удаленным экземпляром MongoDb .
- Использование @Steps Thucydides создаст экземпляр библиотеки предыдущего шага.
- И, наконец, аннотация @UsingDataSet для заполнения данных в базе данных MongoDb перед запуском теста.
{
"book":[
{
"title": "The Lord Of The Rings",
"numberOfPages": "1299",
"cover": "http:\/\/upload.wikimedia.org\/wikipedia\/en\/6\/62\/Jrrt_lotr_cover_design.jpg"
},
{
"title": "The Hobbit",
"numberOfPages": "293",
"cover": "http:\/\/upload.wikimedia.org\/wikipedia\/en\/4\/4a\/TheHobbit_FirstEdition.jpg"
}
]
}
Обратите внимание, что
NoSQLUnit поддерживает базу данных в известном состоянии, очищая базу данных перед каждым выполнением теста и заполняя ее известными данными, определенными в
файле json .
Также имейте в виду, что этот пример очень прост, поэтому было показано только небольшое подмножество возможностей
Thucydides и
NoSQLUnit . Следите за обоими сайтами:
http://thucydides.info и
https://github.com/lordofthejars/nosql-unit.
Мы продолжаем учиться,
Алекс.
Любовь — это горящая вещь, и она создает огненное кольцо, связанное диким желанием, я попадаю в кольцо огня (кольцо огня — Джонни Кэш)
