Selenium UI test is the most used high level test these days for web applications. Regardless of which language you use, the framework is pretty much the same. I would like to share with everybody the Selenium web driver testing framework I worked on recently using Selenium in Java on a Groovy Gradle framework.
I will provide the step-by-step guideline on how to create a skeleton framework from scratch:
-
Import libraries you need
dependencies { compile 'org.codehaus.groovy:groovy-all:2.4.3' testCompile 'junit:junit:4.12' testCompile 'org.seleniumhq.selenium:selenium-java:2.46.0' testCompile 'info.cukes:cucumber-groovy:1.2.3' }
You will need the Selenium Java from Maven repository, Cucumber in Groovy as a BDD layer (although this is not necessary), JUnit to assert test values.
2. Create a webdriver class
import org.openqa.selenium.WebDriver import org.openqa.selenium.WebElement import org.openqa.selenium.chrome.ChromeDriver public class CsWebDriver { private static WebDriver _driver public static WebDriver get(String browserType) { if (browserType.equals("chrome")) { System.setProperty("webdriver.chrome.driver","srcmainresourceschromedriver.exe") ChromeOptions options = new ChromeOptions(); options.setBinary("c:Chrome.V41GoogleChromePortable.exe"); _driver=new ChromeDriver(options) } return _driver }
This is where we declare a new web driver object from the library and initialize it with a copy of driver downloaded from ChromeDriver. You could create or extend all browser related functionalities in this class, such as Open a URL, Quit, Wait, Move To Click, etc.
For example: Move to an element to click using Action class
public static WebElement WaitTillElementExist(WebElement ele, int seconds) { WebDriverWait wait = new WebDriverWait(_driver,seconds) return wait.until(ExpectedConditions.elementToBeClickable(ele)) }
3. Create Page Factory to host Page Objects
public class PageFactory { private static WebDriver _driver public static LoginPage LoginPagepublic static void InitialisePages(WebDriver driver) { _driver=driver LoginPage= new LoginPage(driver) }public static void ResetPages() { LoginPage=null } public static GetDriver() { return _driver }
Page Factory above is where we declare, initialize, and reset our Page Objects. An instance of web driver will be passed into each Page Object.
import org.openqa.selenium.support.FindBy import org.openqa.selenium.support.How @InheritConstructors class LoginPage extends BasePage { @FindBy(how=How.ID, using="Username") private WebElement userName @FindBy(how=How.ID, using="Password") private WebElement password@FindBy(how=How.CSS, using="button[class='btn']") private WebElement loginBtn public void Login(String username, String pwd) { userName.sendKeys(username) password.sendKeys(pwd) loginBtn.click() } }
Every webpage that we are testing is treated as an object. By importing the Selenium library FindBy and How we can select the element that we want using ID, CSS, XPATH, etc. The page object will also contain functions specific to the page, for eg. Login function. As we can see, the page object is extended from the BasePage. A BasePage looks like this:
import org.openqa.selenium.support.PageFactory public class BasePage { public WebDriver driver public BasePage(WebDriver webdriver) { this.driver=webdriver PageFactory.initElements(webdriver,this) } }
We use the Selenium PageFactory library to easily implement this.
4. Binding everything together
So we now have the web driver class, page factory, and page objects, how do we glue this all together into an executable test? To make test easier to understand and read, we usually like to use a BDD tool to describe a test Scenario. I will not go into depth on the BDD tool in this post, but I would like to touch base on the Before Scenario Hook of a BDD tool that is used to glue all pieces together.
this.metaClass.mixin(cucumber.api.groovy.Hooks) this.metaClass.mixin(cucumber.api.groovy.EN) Before("@web") { scenario -> PageFactory.InitialisePages(WebDriver.get("chrome")) WebDriver.Open(oagUrl) }
Before every scenario, we initialize all Page Objects with a Chrome driver and then open the URL.
After("@web") { scenario -> if (scenario.isFailed()) { String fileName=scenario.getName() WebDriver.PrintPageSource() WebDriver.TakeScreenShot(fileName, scenario) } WebDriver.Quit() PageFactory.ResetPages() }
After every scenario, we check if the scenario is failed, if so, we print out the scenario name and take a screen shot. We then quit the driver and reset all Page Objects to null.
5. Run the test via command line
To enable the test to be run on a CI box, we have to make the test run via command line. The example below is using Gradle to run the Cucumber Groovy test:
configurations { cucumberRuntime { extendsFrom testRuntime } }sourceSets{ test{ groovy{ srcDirs 'src/test' } } }task cucumber() { dependsOn assemble, compileTestJava doLast { javaexec { main = "cucumber.api.cli.Main" classpath = configurations.cucumberRuntime + sourceSets.main.output + sourceSets.test.output args = ['-f', 'json:target/cucumber-report.json','--plugin','pretty', '--glue', 'src/test/groovy/au/com/test/story/steps', 'src/test/groovy/au/com/test/story/features'] } } }
We created a Gradle task called “cucumber” and execute the test using “javaexec”. We need to define in the Source Sets the directory of the test. In “args –glue”, we define where the Feature files and Steps Definitions are.