test_structure

Model

The purpose of the model is to define how to access all of the HTML components on the page or pages being tested, and to provide those web elements to the testing class.  This is primarily done by using a utility class called XPathUtils, which contain helper methods for generating the XPath required for getting to every possibly HTML component in numerous ways. The concept is to have a single point handle component access, so that it can be easily found and manipulated should the need arise to make changes, such as when the page or pages being tested have changed.

Example: Form1Model.java

package com.appfoundation.automation.example.model;

import org.openqa.selenium.WebElement;

import com.appfoundation.automation.framework.BaseModel;
import com.appfoundation.automation.framework.BaseSeleniumTest;
import com.appfoundation.automation.util.XPathUtils;

/**
 * The purpose of the model for a screen/view is to define all the XPath needed to
 * access the components within.
 * 
 * @author john.valentino
 *
 */
public class Form1Model extends BaseModel {

	/** Returns the XPath for the first name input */
	public static final String FIRST_NAME_XPATH = XPathUtils.findInputByName("first");
	/** Returns the XPath for the last name input using the XPathUtils class */
	public static final String LAST_NAME_XPATH = XPathUtils.findInputByName("last");
	/** Returns the XPath for the reset button */
	public static final String RESET_XPATH = XPathUtils.findButtonByText("Reset");
	/** Returns the XPath for the submit button using the XPathUtils class */
	public static final String SUBMIT_XPATH = XPathUtils.findButtonByText("Submit");
	/** Returns the XPath for the message box div in ExtJS */
	public static final String MESSAGE_BOX_XPATH = XPathUtils.findExtJsMessageBox();
	/** Returns the XPath for the OK button within the message box div in ExtJS */
	public static final String MESSAGE_BOX_OK_XPATH = XPathUtils.findExtJsMessageBoxButtonByText("OK");

	public Form1Model(BaseSeleniumTest test) {
		super(test);
	}

	public WebElement findFirstName() {
		return this.find(FIRST_NAME_XPATH);
	}

	public WebElement findLastName() {
		return this.find(LAST_NAME_XPATH);
	}

	public WebElement findSubmit() {
		return this.find(SUBMIT_XPATH);
	}

	public WebElement findMessageBox() {
		return this.find(MESSAGE_BOX_XPATH);
	}

	public WebElement findMessageBoxOk() {
		return this.find(MESSAGE_BOX_OK_XPATH);
	}

	public WebElement findReset() {
		return this.find(RESET_XPATH);
	}
}

Base Test

The purpose of the base test class is to define one or more tests for a page or series of pages, as expected to be able to run in any browser, and to assert the expected results. The base test class defines the actual test methods, and uses the defined model in order the HTML components within the page or pages being tested. A base test class extends the BaseSeleniumTest, and defines the model that it uses for component interaction. Individual test methods use the JUnit @Test annotation.

Example: Form1TestBase.java

package com.appfoundation.automation.example;

import static org.junit.Assert.*;

import org.junit.Test;
import org.openqa.selenium.WebElement;

import com.appfoundation.automation.example.model.Form1Model;
import com.appfoundation.automation.framework.BaseSeleniumTest;

public class Form1TestBase extends BaseSeleniumTest {

	private Form1Model model;

	public Form1TestBase() {
		this.model = new Form1Model(this);
	}

	@Test
	public void testResetForm()  {

		// Load the URL of the page to test
		driver.get(this.getBaseUrl()+"/form1.html");

		// wait until one or more of the elements you want to interact with have become available
		this.waitToBeClickable(Form1Model.FIRST_NAME_XPATH);

		// For evidence of testing, take a screenshot of the initial screen
		this.outputScreenShot();

		WebElement firstNameField = model.findFirstName();
		WebElement lastNameField = model.findLastName();
		WebElement resetButton = model.findReset();

		// Type the information into the form
		firstNameField.sendKeys("John");
		lastNameField.sendKeys("Valentino");

		// verify the information was inputed correctly
		assertEquals("John", firstNameField.getAttribute("value"));
		assertEquals("Valentino", lastNameField.getAttribute("value"));

		// For evidence of testing, take a screen shot of the screen with the form filled out
		this.outputScreenShot();

		// press the reset button
		resetButton.click();

		// verify the information was cleared from the form
		assertEquals("", firstNameField.getAttribute("value"));
		assertEquals("", lastNameField.getAttribute("value"));

		// For evidence of testing, take a screen shot of the screen with the form cleared
		this.outputScreenShot();

	}
}

Test classes have several utilities built into them such as for waiting for other components to be visible or in some other state, and for common actions like performing drag and drops as well as double-clicks. These types of utility functionality methods reside in the TestUtils class. You can also run the a base test class by itself out of the IDE by running it as a JUnit test, (In Eclipse right-click on the file and select “Run as -> JUnit Test”). This will run the test in the default testing browser, which by default is Chrome.

Test Implementation Class

The purpose of the test implementation class to to define the browser in which a test will run, and to override any test methods that require browser specific interactions.  It does this by inheriting from the base test class and specifying the browser using the BrowserType annotation.

For example in most cases Chrome will work out-of-the-box, so tests involving Chrome typically will not contain any overrides:

Example: Form1ChromeTest.java

package com.appfoundation.automation.example.test;

import com.appfoundation.automation.example.Form1TestBase;
import com.appfoundation.automation.framework.Browser;
import com.appfoundation.automation.framework.BrowserType;

@BrowserType(value = Browser.CHROME)
public class Form1ChromeTest extends Form1TestBase {

}

Another example would be if you had to do something different, because Internet Explorer is not playing nice in some a capacity. This can be done by override the test method and filling in the implementation details there.

Example: Form1IETest.java

package com.appfoundation.automation.example.test;

import org.junit.Test;

import com.appfoundation.automation.example.Form1TestBase;
import com.appfoundation.automation.framework.Browser;
import com.appfoundation.automation.framework.BrowserType;

@BrowserType(value = Browser.INTERNET_EXPLORER)
public class Form1IETest extends Form1TestBase {

	@Test
	@Override
	public void testResetForm()  {
		driver.get(this.getBaseUrl()+"/form1.html");

		// do stuff specific to IE here instead
	}

}

The test implementation classes can also be run out of the IDE by running them as a JUnit test as well, which will run them in the browser specified by the annotation.

What Next?

See Supported Browsers.