Skip to content
This repository has been archived by the owner on Feb 22, 2019. It is now read-only.

webtest

Pavel Vlasov edited this page Aug 2, 2014 · 23 revisions

WebTest

Nasdanika WebTest is a Web UI automated testing and documentation generation framework built on Selenium WebDriver and JUnit.

The framework provides JUnit test runner class and test suite runner classes which generate an HTML report with detailed screenshots after test/suite execution. Screenshots are collected transparently by intercepting invocations of test, actor, and page methods.

The framework encourages separation of actor/page specification and implementation. Such separation enables parallelization of development of tests and actor/page implementations against page specifications. It also allows to write page/actor implementation-independent tests and run them against different implementations.

The framework also provides several annotations which allow to customize test execution and report generation.

Concepts

  • Test case - a JUnit 4 test case class which implements WebTest interface and runs with NasdanikaTestRunner. The test case shall obtain an instance of WebDriver in @Before method and also create proxies of actor and page factories by invoking NasdanikaTestRunner.proxyActorFactory() and NasdanikaTestRunnar.proxyPageFactory(). It also shall quit the driver in @After method.
  • Test method - a JUnit test method, NasdanikaTestRunner take a screenshot before and after test method execution. Test methods may operate with web driver directly, but it is recommended to use actor and page layers of abstraction.
  • Page - an interface/class pair which provides a facade for test/actor code to interact with a Web page. It abstracts test/actor code from details of the page implementation. For WebTest to be able to record page method invocations and take snapshots, pages must be defined as interfaces extending Page interface. See Page Object for additional information.
  • PageFactory - a factory interface for creating pages.
  • Actor - an interface/class pair which groups fine-grained operations on a page or a group of pages into coarse-grained business methods.
  • ActorFactory - a factory interface for creating actors.

Annotations

  • Report - can be applied to a test class - case or suite - to customize report generation.
  • Title - applies to test/actor/page classes and methods to customize how given class/method appears in the report. If this annotation is not provided the title is constructed from class/method name by splitting class/method name by camel case character class, capitalizing the first word and lower-casing the others. E.g. a title for myVeryComplexTest() method would be My very complex test.
  • Description - allows to attach a description to class/method to appear in the report.
  • Pending - test methods with this annotation are not executed but included into the report. Tests which don't call any page or actor methods are automatically marked as pending.

Usage scenarios

Single application

This scenario is realized in Example Bank Application. The diagram below depicts a partial plug-in dependency graph:

Partial Dependency Graph

This bundle is a fragment for org.nasdanika.examples.bank.app. Tests can be executed either as an OSGi application TestRunner (e.g. in Eclipse IDE), or as Maven/Tycho eclipse-test-plugin (e.g. during an automated build by Jenkins). This bundle contains tests which operate with actors and pages. The code snippet below shows part of the Registration test:

@RunWith(NasdanikaTestRunner.class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Description("Tests of registration scenarios")
public class Registration implements WebTest {
	
	private WebDriver driver;
	
	@Override
	public WebDriver getWebDriver() {
		return driver;
	}
	
	private BankActorFactory actorFactory;

	@Before
	public void setUp() throws Exception {
        driver = new FirefoxDriver(); // new ChromeDriver();
        driver.manage().timeouts().pageLoadTimeout(3, TimeUnit.SECONDS);
        BankPageFactory pageFactory = NasdanikaTestRunner.proxyPageFactory(new BankPageFactoryImpl(driver, "http://localhost:8080"));
        actorFactory = NasdanikaTestRunner.proxyActorFactory(new BankActorFactoryImpl(pageFactory));
	}
	
	@Test
	@Description("Successful registration")
	public void aHappyPath() throws Exception {
		Guest guest = actorFactory.createGuest();
		Actor customer = guest.signUp("jDoe", "John Doe", "J0hn$D03", "J0hn$D03");
		Assert.assertTrue(customer instanceof Customer);
		Assert.assertTrue(customer.getCurrentPage() instanceof CustomerHome);
		Assert.assertEquals("John Doe", ((CustomerHome) customer.getCurrentPage()).getBanner());
	}

This bundle contains actors and actor factory specifications. E.g. Guest actor is defined as:

@Description("Unauthenticated user")
public interface Guest extends Actor {
	
	/**
	 * 
	 * @param user
	 * @param password
	 * @return Actor for the authenticated user (Customer) if log-in succesful, 
	 * self otherwise.
	 */
	@Description("Enter Online ID and Password and click 'Sign in' button.")
	Actor signIn(String onlineId, String password);

	/**
	 * Registers new customer.
	 * @param onlineId
	 * @param name
	 * @param password
	 * @param passwordConfirmation
	 * @return Customer if sign-up successful, Guest otherwise.
	 */
	Actor signUp(String onlineId, String name, String password, String passwordConfirmation);

}

This bundle contains actors and actor factory implementations. Actor implementatios operate on page specifications as demonstrated in the snippet below, which shows GuestImpl.signuUp() method:

@Override
public Actor signUp(
		String onlineId, 
		String name, 
		String password,
		String passwordConfirmation) {
	GuestHome home = factory.getPageFactory().createGuestHome();
	home.open();
	currentPage = home;
	Page signUpResult = home.clickSignUp()
			.waitToAppear()
			.enterOnlineId(onlineId)
			.enterName(name)
			.enterPassword(password)
			.enterPasswordConfirmation(passwordConfirmation)
			.clickSignUp();

	if (signUpResult instanceof CustomerHome) {
		Assert.assertEquals(name, ((CustomerHome) signUpResult).getBanner());
		return factory.createCustomer((CustomerHome) signUpResult);
	} 
	return this;
}

This is a page specification bundle, it contains page and page factory interfaces, e.g. GuestHome page interface:

public interface GuestHome extends Page {

	/**
	 * Navigates to the home page.
	 */
	void open();

	void enterOnlineId(String onlineId);

	void enterPassword(String password);

	/**
	 * Clicks sign-in button.
	 * @return Customer home if sign-in was successful, this page if input validation fails, or authentication failed dialog 
	 * if incorrect credentials were provided.
	 */
	Page clickSignIn();

	SignUpDialog clickSignUp();	
}

This is page implementation bundle. Page implementations use Selenium WebDriver to drive browsers as shown in a fragment of GuestHomeImpl below:

public class GuestHomeImpl implements GuestHome {

	private BankPageFactoryImpl factory;
	private WebDriver webDriver;

	public GuestHomeImpl(WebDriver webDriver) {
		this.webDriver = webDriver;
	}

	public void setFactory(BankPageFactoryImpl factory) {
		this.factory = factory;
	}

	private WebElement onlineId;
	private WebElement password;
	private WebElement signInButton;

	private WebElement signUpMenuItem;

	@Override
	public void enterOnlineId(String onlineId) {
		this.onlineId.sendKeys(onlineId);
	}

	@Override
	public void enterPassword(String password) {
		this.password.sendKeys(password);
	}

Software product lines

Consistent experience through reuse.

Services

Parallel development of tests/actor libs and page implementations against page specs.

Multiple page and actor libraries, independence of tests from implementations - services/extensions

Integration

If WebServices/RESTful are not available - share you actor/page libs with your partners.

Clone this wiki locally