DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Because the DevOps movement has redefined engineering responsibilities, SREs now have to become stewards of observability strategy.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Related

  • What Is SQL Injection and How Can It Be Avoided?
  • Organizing Knowledge With Knowledge Graphs: Industry Trends
  • A Developer's Guide to Database Sharding With MongoDB
  • Kafka Link: Ingesting Data From MongoDB to Capella Columnar

Trending

  • Scaling Microservices With Docker and Kubernetes on Production
  • Using Java Stream Gatherers To Improve Stateful Operations
  • Advancing Your Software Engineering Career in 2025
  • Efficient API Communication With Spring WebClient
  1. DZone
  2. Data Engineering
  3. Databases
  4. Writing Acceptance Tests for Openshift and MongoDb Applications

Writing Acceptance Tests for Openshift and MongoDb Applications

By 
Alex Soto user avatar
Alex Soto
·
Dec. 09, 12 · Interview
Likes (0)
Comment
Save
Tweet
Share
5.7K Views

Join the DZone community and get the full member experience.

Join For Free

Acceptance testing is used to determine if the requirements of a specification are met. It should be run in an environment as similar as possible of the production one. So if your application is deployed into Openshift, you will require a parallel account to the one used in production for running the tests. In this post we are going to write an acceptance test for an application deployed into Openshift that uses MongoDb as database backend.

The application deployed is a simple library which returns all the books available for lending. This application uses MongoDb for storing all information related to books.
So let's start describing the goal, feature, user story, and acceptance criteria for previous applications.
Goal: Expanding a lecture to the most people.
Feature: Display available books.
User Story: Browse Catalog -> In order to find books I would like to borrow, As a User, I want to be able to browse through all books.
Acceptance Criteria: Should see all available books.
Scenario:
Given I want to borrow a book
When I am at catalog page
Then I should see information about available books: The Lord Of The Jars - 1299 - LOTRCoverUrl , The Hobbit - 293 - HobbitCoverUrl
Notice that this is a very simple application, so the acceptance criteria is simple too.
For this example, we need two test frameworks, the first one for writing and running acceptance tests, and the other one for managing the NoSQL backend. In this post we are going to use Thucydides for ATDD and NoSQLUnit for dealing with MongoDb.
The application is already deployed in Openshift, and you can take a look at https://books-lordofthejars.rhcloud.com/GetAllBooks


Thucydides
is a tool designed to make writing automated acceptance and regression tests easier. 
Thucydides uses WebDriver API to access HTML page elements. But it also helps you to organise your tests and user stories by using a concrete programming model, create reports of executed tests, and finally it also measures functional cover. 
To write acceptance tests with Thucydides next steps should be followed. 
  • First of all, choose a user story of one of your features. 
  • Then implement the PageObject class. PageObject is a pattern which models web application's user interface elements as objects, so tests can interact with them programmatically.  Note that in this case we are coding "how" we are accessing to html page.
  • Next step is implementing steps library. This class will contain all steps that are required to execute an action. For example creating a new book requires to open addnewbook page, insert new data, and click to submit button. In this case we are coding "what" we need to implement the acceptance criteria.
  • And finally coding the chosen user story following defined Acceptance Criteria and using previous step classes.
NoSQLUnit is a JUnit extension that aims us to manage lifecycle of required NoSQL engine, help us to maintain database into known state and standarize the way we write tests for NoSQL applications. NoSQLUnit is composed by two groups of JUnit rules,  and two annotations. In current case, we don't need to manage lifecycle of NoSQL engine, because it is managed by external entity (Openshift).
So let's getting down on work:

First thing we are going to do is create a feature class which contains no test code; it is used as a way of representing the structure of requirements.
public class Application {

    @Feature
    public class Books {
        public class ListAllBooks {}
    }

}

Note that each implemented feature should be contained within a class annotated with @Feature annotation. Every method of featured class represents a user story.
Next step is creating the PageObject class. Remember that PageObject pattern models web application's user interface as object. So let's see the html file to inspect what elements must be mapped.
<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>

The most important thing here is that table tag has an id named listBooks which will be used in PageObject class to get a reference to its parameters and data. Let's write the page object:
@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();
}
};
}

}
Using @DefaultUrl we are setting which URL is being mapped, with @FindBy we map the web element with id listBooks, and finally getBooksTable() method which returns the content of generated html table.

The next thing to do is implementing the steps class; in this simple case we only need two steps, the first one that opens the GetAllBooks page, and the other one which asserts that table contains the expected elements.
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);
}

}

And finally class for validating the acceptance criteria:

@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();
}

}

There are some things that should be considered in previous class:
  • @Story should receive a class defined with @Feature annotation, so Thucydides can create correctly the report.
  • We use MongoDbRule to establish a connection to remote MongoDb instance. Note that we can use localhost address because of port forwarding Openshift capability so although localhost is used, we are really managing remote MongoDb instance.
  • Using @Steps Thucydides will create an instance of previous step library.
  • And finally @UsingDataSet annotation to populate data into MongoDb database before running the test.
{
"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"
}
]
}



Note that NoSQLUnit maintains the database into known state by cleaning database before each test execution and populating it with known data defined into a json file.
Also keep in mind that this example is very simple so only and small subset of capabilities of Thucydides and NoSQLUnit has been shown. Keep watching both sites: http://thucydides.info and https://github.com/lordofthejars/nosql-unit
We keep learning,
Alex.
Love Is A Burning Thing, And It Makes A Fiery Ring, Bound By Wild Desire, I Fell Into A Ring Of Fire (Ring of Fire - Johnny Cash)






Web application Testing MongoDB OpenShift Database Book

Opinions expressed by DZone contributors are their own.

Related

  • What Is SQL Injection and How Can It Be Avoided?
  • Organizing Knowledge With Knowledge Graphs: Industry Trends
  • A Developer's Guide to Database Sharding With MongoDB
  • Kafka Link: Ingesting Data From MongoDB to Capella Columnar

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!