March 31, 2017

Learning Serenity: Scaffolding a new project with Maven Archetypes

Imagine that you are starting a new job, where you encounter yet another new automated toolset you haven't heard of before. It means that you have:


This is why I blog: The only way to keep my head on straight is to take copious amounts of research notes. This blog is where I store them.

Am I struggling with a concept that I just can't get? I've befriended a few experts in my very short time as an automation developer (Hi, Alan, Dave, Joe, Jim, James M, Joon, Lark, Martin, James V, Bas, and Angie!) who really enjoy helping out beginners like me out. If I blog about a problem I am having, and point to the post on Twitter, I get excellent feedback from the automation community. Thank you all so much!



Take a look at January 2016's project, Automate Amazon. You have:

  • Build Configuration file, written as either with Apache Maven pom.xml file or a Gradle build.gradle file to set up all the third party dependencies. 
  • Test script classes written in frameworks such as JUnit, TestNG or Spock to execute the tests. 
  • Page Object classes that encapsulate the functionality on the page such as dropdown list boxes, radio buttons and text boxes. Public methods are created to, say, investigate the header text, or enter text into a textbox. 
  • Action classes that bundle the page object methods together, such as when you want to loginAs(String username, String password), and want to combine methods to enter usernames, passwords, and click on Login buttons. 
  • Driver classes that set up the browser you are going to run the web user interface test on. 

There are so many pre-conditions and moving parts, how the heck can anyone keep it all straight!

Luckily, there are scaffolding tools: Software tools that build out a skeleton of a project, sample working code, and the folder structure. Some tools, such as this Yeoman generator, are written by fans of the product. Some, though, are written by the author of the automation toolset, itself!

For this blog post, we will be taking a look at Maven Archetypes, especially the ones that John Ferguson Smart, is the founder and lead developer of Serenity BDD created.

What Is Apache Maven

From the Apache Maven Project: What is Maven?

"Maven, a Yiddish word meaning accumulator of knowledge, was originally started as an attempt to simplify the build processes in the Jakarta Turbine project. There were several projects each with their own Ant build files that were all slightly different and JARs were checked into CVS. We wanted a standard way to build the projects, a clear definition of what the project consisted of, an easy way to publish project information and a way to share JARs across several projects.

"The result is a tool that can now be used for building and managing any Java-based project. We hope that we have created something that will make the day-to-day work of Java developers easier and generally help with the comprehension of any Java-based project".


What Is A Maven Archetype

From the Apache Maven Project: What is an Archetype:

"In short, Archetype is a Maven project templating toolkit. An archetype is defined as an original pattern or model from which all other things of the same kind are made. The names fits as we are trying to provide a system that provides a consistent means of generating Maven projects. Archetype will help authors create Maven project templates for users, and provides users with the means to generate parameterized versions of those project templates.

"Using archetypes provides a great way to enable developers quickly in a way consistent with best practices employed by your project or organization. Within the Maven project we use archetypes to try and get our users up and running as quickly as possible by providing a sample project that demonstrates many of the features of Maven while introducing new users to the best practices employed by Maven. In a matter of seconds a new user can have a working Maven project to use as a jumping board for investigating more of the features in Maven. We have also tried to make the Archetype mechanism additive and by that we mean allowing portions of a project to be captured in an archetype so that pieces or aspects of a project can be added to existing projects. A good example of this is the Maven site archetype. If, for example, you have used the quick start archetype to generate a working project you can then quickly create a site for that project by using the site archetype within that existing project. You can do anything like this with archetypes".

How Do We Use A Maven Archetype?

From a Command Line utility, such a Mac Terminal, you start off calling an archetype like so:

mvn archetype:generate

.. And follow it by the Maven Archetype Plugin you want. For example, if you take a look at Serenity's GitHub page, you will find https://github.com/serenity-bdd/serenity-maven-archetypes

serenity-cucumber-archetype
serenity-jbehave-archetype
serenity-junit-archetype
serenity-junit-screenplay-archetype

There are so many choices! Which one should I pick?

Okay! I will start with the Screenplay pattern! Thank you, Serenity BDD for your help!

You can see it stored in the Maven Repository at https://mvnrepository.com/artifact/net.serenity-bdd/serenity-junit-screenplay-archetype and see that it was updated January 2017.

  • Open up a Mac Terminal 
  • Enter the following: mvn archetype:generate serenity-junit-screenplay-archetype

What happens next? Take a look at Serenity BDD's Screenplay Tutorial at http://serenity-bdd.info/docs/articles/screenplay-tutorial.html

Choose archetype:
1: remote -> net.serenity-bdd:serenity-junit-screenplay-archetype (Serenity automated acceptance testing project using Screenplay, Selenium 2 and JUnit)
Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): :
"This will (after downloading list all of the available Serenity screenplay archetypes. For this tutorial, we will be working with JUnit, so enter the number corresponding to the net.serenity-bdd:serenity-junit-screenplay-archetypeentry ("1" in the example shown here).

"You will then be prompted to enter a groupId, artifactId, and version for your project, and a root package for your classes"
.
Choose a number or apply filter (format: [groupId:]artifactId, case sensitive contains): : 1
Define value for property 'groupId': : net.serenitybdd.tutorials
Define value for property 'artifactId': : todomvctests
Define value for property 'version':  1.0-SNAPSHOT: : 1.0.0-SNAPSHOT
Define value for property 'package':  net.serenitybdd.tutorials: :
Confirm properties configuration:
groupId: // Entered com.tjmaher.com.serenity-archetype-generated
artifactId: // Entered serenity-archetype-generated

version: 1.0.0-SNAPSHOT
package: [Default]
 Y: : Y
"Maven will now generate a project skeleton for you":



Y: : Y
[INFO] ----------------------------------------------------------------------------
[INFO] Using following parameters for creating project from Archetype: serenity-junit-screenplay-archetype:1.1.19
[INFO] ----------------------------------------------------------------------------
[INFO] Parameter: groupId, Value: net.serenitybdd.tutorials
[INFO] Parameter: artifactId, Value: todomvctests
[INFO] Parameter: version, Value: 1.0.0-SNAPSHOT
[INFO] Parameter: package, Value: net.serenitybdd.tutorials
[INFO] Parameter: packageInPathFormat, Value: net/serenitybdd/tutorials
[INFO] Parameter: package, Value: net.serenitybdd.tutorials
[INFO] Parameter: version, Value: 1.0.0-SNAPSHOT
[INFO] Parameter: groupId, Value: net.serenitybdd.tutorials
[INFO] Parameter: artifactId, Value: todomvctests
[INFO] project created from Archetype in dir: /Users/john/Projects/OpenSource/serenity/serenity-articles/screenplay-tutorial/sample-code/screenplay-tutorial
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 04:52 min
[INFO] Finished at: 2016-02-15T09:16:05+00:00
[INFO] Final Memory: 16M/309M
[INFO] ------------------------------------------------------------------------
Want to examine the sample code? I uploaded the code to my GitHub repository.

What does the Sample Project Do?

Under src/main/java:

Page Objects Generated:

Imagine if you were going to automate Wiktionary.com, encapsulating the functionality of the page into a Page Object. How would you do that? Here is how Jon Smart did it:

DictionaryPage.java: An abstraction of the Wiktionary page.
  • The annotation @DefaultUrl points to the web address of the page. 
  • The class is set to extend Serenity's Page Object class.
  • Using the PageFactory implementation and @FindBy annotations, it maps out the search textbox and the go button as "searchTerms" and "lookupButton". 
  • Declares public methods "enter_keywords(String keyword)" and "lookup_terms". First method uses the WebDriver "type" method to enter keyword data into "searchTerms", and the second uses the WebDriver "click" method to press the button. 
  • It uses the Serenity class WebElementFacade to create a definition list. 
  • It uses ch.lambdaj.Lambda.convert to convert the text to Strings.

Under src/test/java:

Requirements: Application.java
 public class Application {  
   @Feature  
   public class Search {  
     public class SearchByKeyword {}  
     public class SearchByMultipleKeywords {}  
   }  
 }  
... Need a Search feature? Here one is!

Steps: See EndUserSteps.java
 import static ch.lambdaj.Lambda.join;  
 import static org.hamcrest.MatcherAssert.assertThat;  
 import static org.hamcrest.Matchers.containsString;  
 import static org.hamcrest.Matchers.hasItem;  
 public class EndUserSteps extends ScenarioSteps {  
   DictionaryPage dictionaryPage;  
   @Step  
   public void enters(String keyword) {  
     dictionaryPage.enter_keywords(keyword);  
   }  
   @Step  
   public void starts_search() {  
     dictionaryPage.lookup_terms();  
   }  
   @Step  
   public void should_see_definition(String definition) {  
     assertThat(dictionaryPage.getDefinitions(), hasItem(containsString(definition)));  
   }  
   @Step  
   public void is_the_home_page() {  
     dictionaryPage.open();  
   }  
   @Step  
   public void looks_for(String term) {  
     enters(term);  
     starts_search();  
   }  
 }  

Jon Smart is using:

  • Lamda join to make magic. 
  • Hamcrest's assertThat to make things more readable. 
  • It uses the methods we declared with the DictionaryPage page object to interact with the web page itself. 
  • Note that all these methods are set as variables. These steps can be reused again and again to search for different keywords, such as "apple" or "banana". 

And last but not least, we have...

Story: SearchByKeywordStoryTest.java
 @Story(Application.Search.SearchByKeyword.class)  
 @RunWith(ThucydidesRunner.class)  
 public class SearchByKeywordStoryTest {  
   @Managed(uniqueSession = true)  
   public WebDriver webdriver;  
   @ManagedPages(defaultUrl = "http://en.wiktionary.org/wiki/Wiktionary")  
   public Pages pages;  
   @Steps  
   public EndUserSteps endUser;  
   @Issue("#WIKI-1")  
   @Test  
   public void searching_by_keyword_apple_should_display_the_corresponding_article() {  
     endUser.is_the_home_page();  
           endUser.looks_for("apple");  
     endUser.should_see_definition("A common, round fruit produced by the tree Malus domestica, cultivated in temperate climates.");  
   }  
   @Test  
   public void searching_by_keyword_banana_should_display_the_corresponding_article() {  
     endUser.is_the_home_page();  
           endUser.looks_for("pear");  
           endUser.should_see_definition("An edible fruit produced by the pear tree, similar to an apple but elongated towards the stem.");  
   }  
   @Pending @Test  
   public void searching_by_ambiguious_keyword_should_display_the_disambiguation_page() {  
   }  
 }   

This puts everything together! In this Story it:

  • Creates an Actor called "endUser".
  • The actor can use methods declared in EndUserSteps Jon Smart created such as "looks_for" and "should_see_definition".
These actors are part of the abstract concept Jon Smart calls "The Screenplay Pattern". The next blog entry, we will look into Jon's Screenplay Tutorial at http://serenity-bdd.info/docs/articles/screenplay-tutorial.html



Until then, Happy Testing!



-T.J. Maher

Twitter | LinkedIn | GitHub

// Sr. QA Engineer, Software Engineer in Test, Software Tester since 1996.
// Contributing Writer for TechBeacon.
// "Looking to move away from manual QA? Follow Adventures in Automation on Facebook!"

No comments: