Basic overview of software design patterns

Last Updated on by

Post summary: Basic overview of design patterns.

Although I have touched on the topic of design patterns in my Design patterns every test automation engineer should know post, I wanted for a long time to bring an article on the full topic. It is an important topic for software developers because knowing it or not they are in our everyday life. We need to be able to properly structure our code, so it is better that we are aware of them. In the current post, I will just give an overview of the patterns, the implementation details can be found all over the internet. I like Design Patterns in Java Tutorial because it is simple and is a very good starting point, and The Catalog of Design Patterns gives much more details and use-cases.

Design patterns

Design patterns give guidance on how to solve common scenarios and how to structure the code during software development. The main goal of using design patterns is to make the code easy to maintain, hence reducing the maintainability costs. Design patterns are split into several groups: creational patterns, structural patterns, and behavioral patterns.

Creational patterns

Patterns in this group are concerned about the creation of objects in a commonplace, rather than using the new operator where a new object is needed. This provides better re-usability and control over how objects are created. Please check the Creational patterns rules of thumb section which gives a very good overview of differences and combinations of the design patterns.

  • Factory Method – One class is responsible for creating different objects which implement one and the same interface. Object creation is done in one step by the factory method, which accepts arguments to define what type of object is needed.
  • Abstract Factory – A factory of factories used to create objects with similar characteristics. One class is responsible to create factory objects which are later used to create objects with their factory methods.
  • Builder – Builds complex objects step by step. The same builder process can be used to create different objects depending on the use case.
  • Object Pool – Cache objects in order to increase performance in case of too many expensive objects being created, but not that many are in use.
  • Prototype – Keeps an instance of an object, which is used to create a new object by cloning the cached one. Used in cases where the initial object creation requires significant resources and copying the prototype is a much faster operation.
  • Singleton – Ensures that only one instance of an object is available in the system. The object can be instantiated on-demand or on system startup by static block.

Structural patterns

Patterns in this group are concerned about object composition or representation. They optimize the objects and their relations. Please check the Structural patterns rules of thumb section which gives a very good overview of differences and combinations of the design patterns.

  • Adapter – Connects two incompatible interfaces. An object wraps a class implementing one of the interfaces, then this object implements the methods of the other interface.
  • Bridge – Separates an object’s interface from its implementation.
  • Filter – Filters set of objects based on different criteria or logical operators. Concrete criteria and operators are classes, implementing the criteria interface.
  • Composite – Compose objects into tree structures to represent whole-part hierarchies. An object can contain a list of similar objects, which are related somehow to it.
  • Decorator – Adds new functionalities to already existing objects, by using composition instead of inheritance. The decorator class holds an instance of the object and uses its functionality, it also can add more functionalities along with existing ones.
  • Facade – Defines higher-level interface on top of existing complex interfaces in order to ease the usage of the existing interfaces by hiding the complexity.
  • Flyweight – Reduces the number of created objects by caching and re-using already existing similar objects.
  • Private Class Data – Encapsulates the data of the class into a separate data class and controls access to the data.
  • Proxy – Controls access to another object.

Behavioral patterns

Patterns in this group are concerned about communication and interaction between objects. Please check the Behavioral patterns rules of thumb section which gives a very good overview of differences and combinations of the design patterns.

  • Chain of responsibility – Provides a series of processing objects which sequentially process a request. Objects in the chain decide which one is the most appropriate to process the request and whether to end processing or continue with the next handler.
  • Command – Decouples the object invoking the operation from the one executing it by encapsulating a command request as an object which then is passed to the invoking object.
  • Interpreter – Provides a way to evaluate language grammar or expression. The pattern uses a class to represent each grammar rule. Each rule is either composite or terminal, they are used together to solve the problem.
  • Iterator – Provides a way to access the elements of a collection in a sequential manner without any need to know its underlying representation.
  • Mediator – Define an object that encapsulates and manages how a set of objects interact.
  • Memento – Captures an object’s internal state in order to be able to restore it later.
  • Null Object – Act as a default value of an object. Used when in case of null no action is expected by the system, this removes the need for constant null checking.
  • Observer – Observes for changes and propagates a change of an object to all other objects related to it.
  • State – Changes an object’s behavior when its state changes.
  • Strategy – Encapsulates an algorithm inside a class. Creates objects which represent various strategies and a context object whose behavior varies as per its strategy object.
  • Template method – Defines an abstract class that exposes a predefined way (a template) to execute its methods. Its subclasses can override the method implementation as per need but the invocation is in the same way as defined by an abstract class.
  • Visitor – Represents an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.

Conclusion

The current post gives a basic overview of a very important topic for software engineers, design patterns. Internet is full of resources with more details on how those are implemented.

Related Posts

Read more...

Manage and automatically select needed WebDriver in Java 8 Selenium project

Last Updated on by

Post summary: Example code how to efficiently manage and automatically select needed local WebDriver using Java 8 method reference used as lambda expression.

Code examples in the current post can be found in GitHub selenium-samples-java/design-patterns repository.

Java 8 features

In this example lambda expression and method reference, Java 8 features are used. More in Java 8 features can be found in Java 8 features – Lambda expressions, Interface changes, Stream API, DateTime API post.

Functional interface

Before explaining lambda it is needed to understand the idea of a functional interface as they are leveraged for use with lambda expressions. A functional interface is an interface that has only one abstract method that is to be implemented. A functional interface may or may not have default or static methods (again new Java 8 feature). Although not mandatory, a good practice is to annotate the functional interface with @FunctionalInterface.

Lambda expressions

There is no such term in Java, but you can think of lambda expression as an anonymous method. Lambda expression is a piece of code that provides an inline implementation of a functional interface, eliminating the need for using anonymous classes. Lambda expressions facilitate functional programming and ease development by reducing the amount of code needed.

Method reference

Sometimes when using lambda expression all you do is call a method by name. Method reference provides an easy way to call the method making the code more readable.

Managing WebDriver

The proposed solution of managing WebDriver has enumeration called Browser and class called WebDriverFactory. Another important thing is web drivers should be placed in a folder with name webdrivers and named with a special pattern.

Browser enum

The code is shown below:

package com.automationrhapsody.designpatterns;

import java.util.Arrays;
import java.util.function.Supplier;

import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.ie.InternetExplorerDriver;

public enum Browser {
	FIREFOX("gecko", FirefoxDriver::new),
	CHROME("chrome", ChromeDriver::new),
	IE("ie", InternetExplorerDriver::new);

	private String name;
	private Supplier<WebDriver> driverSupplier;

	Browser(String name, Supplier<WebDriver> driverSupplier) {
		this.name = name;
		this.driverSupplier = driverSupplier;
	}

	public String getName() {
		return name;
	}

	public WebDriver getDriver() {
		return driverSupplier.get();
	}

	public static Browser fromString(String value) {
		for (Browser browser : values()) {
			if (value != null && value.toLowerCase().equals(browser.getName())) {
				return browser;
			}
		}
		System.out.println("Invalid driver name passed as 'browser' property. "
			+ "One of: " + Arrays.toString(values()) + " is expected.");
		return FIREFOX;
	}
}

Enumeration’s constructor has Supplier functional interface as a parameter. When the constructor is called method reference FirefoxDriver::new is called as a lambda expression which purpose is to instantiate new Firefox driver. If only lambda expression is used is would be: () -> new FirefoxDriver(). Notice that method reference is much shorter and easy to read. getDriver() method invokes Supplier’s get() method which is implemented by the lambda expression, so lambda expression is executed hence instantiating new web driver. With this approach Firefox web driver object is created only when getDriver() method is called.

WebDriverFactory

Code is:

package com.automationrhapsody.designpatterns;

import java.io.File;

import org.openqa.selenium.WebDriver;

class WebDriverFactory {

	private static final String WEB_DRIVER_FOLDER = "webdrivers";

		public static WebDriver createWebDriver() {
		Browser browser = Browser.fromString(System.getProperty("browser"));
		String arch = System.getProperty("os.arch").contains("64") ? "64" : "32";
		String os = System.getProperty("os.name").toLowerCase().contains("win") 
				? "win.exe" : "linux";
		String driverFileName = browser.getName() + "driver-" + arch + "-" + os;
		String driverFilePath = driversFolder(new File("").getAbsolutePath());
		System.setProperty("webdriver." + browser.getName() + ".driver", 
				driverFilePath + driverFileName);
		return browser.getDriver();
	}

	private static String driversFolder(String path) {
		File file = new File(path);
		for (String item : file.list()) {
			if (WEB_DRIVER_FOLDER.equals(item)) {
				return file.getAbsolutePath() + "/" + WEB_DRIVER_FOLDER + "/";
			}
		}
		return driversFolder(file.getParent());
	}
}

This code recursively searches for a folder named webdrivers in the project. This is done because when you have a multi-module project running from IDE and from Maven has different root folder and finding web drivers is not possible from both simultaneously. Once the folder is found then proper web driver is selected based on OS and architecture. The code reads browser system property which can be passed from outside hence making the selection of web driver easy to configure. The important part is to have web drivers with special naming convention.

Web drivers naming convention

In order code above to work the web drivers should be placed in webdrivers folder in the project and their names should match the pattern: {DIVER_NAME}-{ARCHITECTURE}-{OS}, e.g. geckodriver-64-win.exe for Windows 64 bit and geckodriver-64-linux for Linux 64 bit.

Conclusion

The proposed solution is a very elegant way to manage your web drivers and select proper one just by passing -Dbrowser={BROWSER} Java system property.

Related Posts

Read more...

Advanced WPF automation – page objects inheritance

Last Updated on by

Post summary: re-use of page objects code through inheritance.

Inheritance is one of the pillars of object-oriented programming. It is a way to re-use functionality of already existing objects.

Reference

I’ve started a series with details of Advanced WPF desktop automation with Telerik Testing Framework and TestStack White. The sample application can be found in GitHub SampleAppPlus repository.

Abstract class

An abstract class is one that cannot be instantiated. An abstract class may or may not have abstract methods. If one method is marked as abstract then its containing class should also be marked as abstract. We have two similar windows with text box, save and cancel button that is shown on both of them. AddEditText class following Page Objects pattern. It is marked as abstract thought. It has an implementation of all three elements except TextBox_Text.

public abstract class AddEditText : XamlElementContainer
{
	protected string mainPath =
		"XamlPath=/Border[0]/AdornerDecorator[0]/ContentPresenter[0]/Grid[0]/";
	public AddEditText(VisualFind find) : base(find) { }

	protected abstract TextBox TextBox_Text { get; }
	private Button Button_Save
	{
		get
		{
			return Get<Button>(mainPath + "Button[0]");
		}
	}
	private Button Button_Cancel
	{
		get
		{
			return Get<Button>(mainPath + "Button[1]");
		}
	}

	public void EnterText(string text)
	{
		TextBox_Text.Clear();
		TextBox_Text.User.TypeText(text, 50);
	}

	public void ClickSaveButton()
	{
		Button_Save.User.Click();
		Thread.Sleep(500);
	}

	public void ClickCancelButton()
	{
		Button_Cancel.User.Click();
	}
}

Add Text page object

The only thing we have to do in Add Text window is to implement TextBox_Text property. All other functionality has already been implemented in AddEditText class.

public class AddText : AddEditText
{
	public static string WINDOW_NAME = "Add Text";
	public AddText(VisualFind find) : base(find) { }

	protected override TextBox TextBox_Text
	{
		get
		{
			return Get<TextBox>(mainPath + "TextBox[0]");
		}
	}
}

Edit Text page object

In Edit Text page object we have to implement “TextBox_Text” property. Also on this window, there is one more element which needs to be defined.

public class EditText : AddEditText
{
	public static string WINDOW_NAME = "Edit Text";
	public EditText(VisualFind find) : base(find) { }

	private TextBlock TextBlock_CurrentText
	{
		get
		{
			return Get<TextBlock>(mainPath + "TextBlock[0]");
		}
	}

	protected override TextBox TextBox_Text
	{
		get
		{
			return Get<TextBox>(mainPath + "TextBox[1]");
		}
	}

	public Verification VerifyCurrentText(string text)
	{
		return BaseTest.VerifyText(text, TextBlock_CurrentText.Text);
	}
}

Conclusion

Inheritance is a powerful tool. We as automation engineers should use it whenever possible.

Related Posts

Read more...

Complete guide how to use design patterns in automation

Last Updated on by

Post summary: Complete code example of how design patterns can be used in real life test automation.

With series of posts, I’ve described 5 design patterns that each automation test engineer should know and use. I’ve started with a brief description of the patterns. Then I’ve explained in details with code snippets following patterns: Page objects, Facade, Factory, Singleton, Null object. Code examples are located in GitHub for C# and Java.

Overview

This post is intended to bond all together in a complete guide how to do write better automation code. Generally, automation project consists of two parts. Automation framework project and tests project. Current guide is intended to describe how to build your automation testing framework. How to structure your tests is a different topic. Remember once having correctly designed framework then tests will be much more clean, maintainable and easy to write. To keep post shorter some of the code that is not essential for representing the idea is removed. The whole code is on GitHub.

Page objects

Everything starts by defining proper page objects. There is no fixed recipe for this. It all depends on the structure of application under test. The general rule is that repeating elements (header, footer, menu, widget, etc) are extracted as separate objects. The whole idea is to have one element defined in only one place (stay DRY)! Below is our HomePage object. What you can do generally is make search and clear search terms. Note that clearing is done with jQuery code. This is because of a bug I’ve described with a workaround in Selenium WebDriver cannot click UTF-8 icons post.

using OpenQA.Selenium;

namespace AutomationRhapsody.DesignPatterns
{
	class HomePageObject
	{
		private WebDriverFacade webDriver;
		public HomePageObject(WebDriverFacade webDriver)
		{
			this.webDriver = webDriver;
		}

		private IWebElement SearchField
		{
			get { return webDriver.FindElement(By.Id("search")); }
		}

		public void SearchFor(string text)
		{
			SearchField.SendKeys(text);
		}

		public void ClearSearch()
		{
			webDriver.ExecuteJavaScript("$('span.cancel').click()");
		}
	}
}

WebDriver factory

WebDriver factory will be responsible for instantiating the WebDriver based on a condition which browser we want to run our tests with.

using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.IE;

namespace AutomationRhapsody.DesignPatterns
{
	public class WebDriverFactory
	{
		public IWebDriver CreateInstance(Browsers browser)
		{
			if (Browsers.Chrome == browser)
			{
				return new ChromeDriver();
			}
			else if (Browsers.IE == browser)
			{
				return new InternetExplorerDriver();
			}
			else
			{
				return new FirefoxDriver();
			}
		}
	}
}

The constructor takes an argument browser type. Browser type is defined as an enumeration. This is very important. Avoid passing back and forth strings. Always stick to enums or special purpose classes. This will save you time investigating bugs in your automation.

public enum Browsers
{
	Chrome, IE, Firefox
}

NullWebElement

This is null object pattern and implements IWebElement. There is a NULL property that is used to compare is given element is not found or no.

using OpenQA.Selenium;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Drawing;

namespace AutomationRhapsody.DesignPatterns
{
	public class NullWebElement : IWebElement
	{
		private const string nullWebElement = "NullWebElement";
		public bool Displayed { get { return false; } }
		public bool Enabled { get { return false; } }
		public Point Location { get { return new Point(0, 0); } }
		public bool Selected { get { return false; } }
		public Size Size { get { return new Size(0, 0); } }
		public string TagName { get { return nullWebElement; } }
		public string Text { get { return nullWebElement; } }
		public void Clear() { }
		public void Click() { }
		public string GetAttribute(string attributeName) { return nullWebElement; }
		public string GetCssValue(string propertyName) { return nullWebElement; }
		public void SendKeys(string text) { }
		public void Submit() { }
		public IWebElement FindElement(By by) { return this; }
		public ReadOnlyCollection<IWebElement> FindElements(By by)
		{
			return new ReadOnlyCollection<IWebElement>(new List<IWebElement>());
		}

		private NullWebElement() { }

		private static NullWebElement instance;
		public static NullWebElement NULL
		{
			get
			{
				if (instance == null)
				{
					instance = new NullWebElement();
				}
				return instance;
			}
		}
	}
}

WebDriver facade

WebDriver facade main responsibility is to define custom behavior on elements location. This gives you centralized control over elements location. The constructor takes browser type and uses the factory to create WebDriver instance which is used internally in the facade. FindElement method defines explicit wait. If the element is not found then NullWebElement which is actual implementation of Null object pattern. The idea is to safely locate elements with try/catch and then just use them skipping checks for null.

using OpenQA.Selenium;
using OpenQA.Selenium.Support.UI;
using System;
using System.Collections.ObjectModel;

namespace AutomationRhapsody.DesignPatterns
{
	public class WebDriverFacade
	{
		private IWebDriver webDriver = null;
		private TimeSpan waitForElement = TimeSpan.FromSeconds(5);

		public WebDriverFacade(Browsers browser)
		{
			WebDriverFactory factory = new WebDriverFactory();
			webDriver = factory.CreateInstance(browser);
		}

		public void Start(string url)
		{
			webDriver.Url = url;
			webDriver.Navigate();
		}

		public void Stop()
		{
			webDriver.Quit();
		}

		public object ExecuteJavaScript(string script)
		{
			return ((IJavaScriptExecutor)webDriver).
				ExecuteScript("return " + script);
		}

		public IWebElement FindElement(By by)
		{
			try
			{
				WebDriverWait wait = new WebDriverWait(webDriver, waitForElement);
				return wait.Until(ExpectedConditions.ElementIsVisible(by));
			}
			catch
			{
				return NullWebElement.NULL;
			}
		}
	}
}

Tests

As I mentioned initially this post is about using efficiently design patterns in your framework automation project. Tests design are not being discussed here. Once you have designed the framework one simple test (without asserts) that makes search will look like the code below.

Browsers browser = Browsers.Chrome;
WebDriverFacade webDriver = new WebDriverFacade(browser);
webDriver.Start("https://automationrhapsody.com/examples/utf8icons.html");

HomePageObject homePage = new HomePageObject(webDriver);
homePage.ClearSearch();
homePage.SearchFor("automation");

webDriver.Stop();

Conclusion

Design patterns are enabling you to write maintainable code. They increase the value of your code. As shown in this series of posts they are not so complicated and you can easily adopt them in your automation. Most important is design patterns increase your value as a professional. So make the time to learn them!

Related Posts

Read more...

Singleton and Null object patterns

Last Updated on by

Post summary: Description with code samples of Singleton and Null object design patterns.

Singleton

Singleton pattern is used in a case where you want to restrict the instantiation of a class to only one object.

More details

The class should not require parameters for its construction. If the creation of a class requires significant resources then a singleton is a suitable solution. It is good that singletons are created when they are first needed, so-called lazy initialization.

Null object pattern

The idea is to make the code simpler and safe by skipping checks for null reference of a given object:

if (someVariable != null) {
	// Do something with someVariable
}

References

This post is part of design patterns guide series. Code examples are located in GitHub for C# and Java.

More details

Null object implements given interface and its methods are doing nothing. This makes the null object more predictable. You can safely invoke methods on the null object without the threat of a NullRefferenceException to break your application. This pattern is very well combined with singleton pattern where a null object is actually a singleton. In this case, you can check for reference or equality.

Example

Most common usage of Singleton pattern is to limit WebDriver to only one object instance in the whole automation test project.

private static IWebDriver webDriver;
public static IWebDriver WebDriver
{
	get
	{
		if (webDriver == null)
		{
			webDriver = new FirefoxDriver();
		}
		return webDriver;
	}
}

I’m going to give slightly different usage example where Singleton is used along with Null object pattern. NullWebElement implements IWebElement interface so it must implement all methods and properties defined by the interface. This is done on lines 4 to 21. Properties are returning some values, but not null! Methods are doing nothing. From line 23 to 36 is the Singleton definition. If Singleton is an object you have defined then it should have a private constructor so no one is able to instantiate it. There is a private field which actually holds the reference to the singleton. NULL is a property which instantiates the singleton if not already instantiated and returns it.

public class NullWebElement : IWebElement
{
	private const string nullWebElement = "NullWebElement";
	public bool Displayed { get { return false; } }
	public bool Enabled { get { return false; } }
	public Point Location { get { return new Point(0, 0); } }
	public bool Selected { get { return false; } }
	public Size Size { get { return new Size(0, 0); } }
	public string TagName { get { return nullWebElement; } }
	public string Text { get { return nullWebElement; } }
	public void Clear() { }
	public void Click() { }
	public string GetAttribute(string attributeName) { return nullWebElement; }
	public string GetCssValue(string propertyName) { return nullWebElement; }
	public void SendKeys(string text) { }
	public void Submit() { }
	public IWebElement FindElement(By by) { return this; }
	public ReadOnlyCollection<IWebElement> FindElements(By by)
	{
		return new ReadOnlyCollection<IWebElement>(new List<IWebElement>());
	}

	private NullWebElement() { }

	private static NullWebElement instance;
	public static NullWebElement NULL
	{
		get
		{
			if (instance == null)
			{
				instance = new NullWebElement();
			}
			return instance;
		}
	}
}

There are two main benefits of code above. The first benefit comes from the Null object pattern. You can locate an element which doesn’t exist and call some of its methods without your tests to crash. You might say that comparing for null is not a big overhead, but in big having a null check before each action is a waste of time.

IWebElement element = null;
try
{
	element = webDriver.FindElement(By.CssSelector("notExisting"));
}
catch
{
	element = NullWebElement.NULL;
}
element.Click();

It might be a discussion whether it is better to silent this failure error with a null object or leave to a massive crash. My opinion is you must fail the test and if you put some logging into Click method of the NullWebElement then you can easily trace the issue. The real benefit is you will have only one failed test instead of the whole bunch failed because of the crash.

The second benefit comes from the Singleton pattern. You can easily compare some element against the NullWebElement.NULL. Most likely you will locate the element and use it safely because of null object pattern, but there might a case where you want to see if the element is actually not found.

if (element == NullWebElement.NULL)
{
	Console.WriteLine("Element not found!");
}

Conclusion

Singleton is a pattern that you definitely should know. A null object with a combination of Singleton can decrease the amount of code you write by skipping the checks for null. I would say if adopted those can simplify your code which is a benefit in big projects.

Related Posts

Read more...

Factory design pattern

Last Updated on by

Post summary: Description of code samples of Factory design pattern.

Factory pattern is used to create objects based on specific rules.

More details

You may have several classes implementing one and the same interface. You might not know what object is suitable to get instantiated at given point in your code. Object creation may depend on different if/else or switch statements. You definitely do not want to make those is/else check every time you need an object. This is why you handle the object creation task to the factory which knows exactly what and how to create an object. The factory always returns a newly created object or re-initialized one.

References

This post is part of design patterns guide series. Code examples are located in GitHub for C# and Java.

Example

In the example I’ve given here, I’ve implemented a factory that creates IWebDriver object based on a specific input. Object creation logic is encapsulated from the outer world. This factory is very simple but is just fine for our purposes. More complex factories are defined by Factory method pattern and Abstract factory pattern but they are suitable for more complex applications. The factory in the example has an only CreateInstance method. In it, WebDriver is instantiated based on given from outside string with its name. It doesn’t store or re-use WebDriver object but always creates a new one.

public class WebDriverFactory
{
	public IWebDriver CreateInstance(string browser)
	{
		if ("Chrome".ToLower() == browser.ToLower())
		{
			return new ChromeDriver();
		}
		else if ("InternetExplorer".ToLower() == browser.ToLower())
		{
			return new InternetExplorerDriver();
		}
		else
		{
			return new FirefoxDriver();
		}
	}
}

A factory is used to instantiate WebDriver in tests. The condition which browser to instantiate may come from external parameter.

WebDriverFactory factory = new WebDriverFactory();
IWebDriver webDriver = factory.CreateInstance("Chrome");
webDriver.Url = "https://automationrhapsody.com";
webDriver.Navigate();

IWebElement logo = webDriver.FindElement(By.CssSelector("div#header-inner h1 a"));
logo.Click();

webDriver.Quit();

Conclusion

A factory is good to be used in automation testing as you have centralized control over WebDriver creation. This pattern will definitely keep you DRY. With the time being, you may add more conditions on object creation (logging, different ports, etc.).

Related Posts

Read more...

Facade design pattern

Last Updated on by

Post summary: Description with code samples of Facade design pattern.

Facade design pattern provides simple and easy to use interface to a larger and more complex code, API or set of APIs.

More details

If you have to deal with complex or poorly designed API you might find yourself confused by all the functionality available in it. Most likely you don’t need everything provided by the API. So for ease and better maintainability, only API features that are needed gets exposed outside the facade. In this way, you simplify the API usage saving time for your colleagues when maintaining this code. Also, you have control over how this external API is used and can prevent misunderstanding or misuse of it. If more functionality from API is needed this will require an update of the facade or adding new facade which exposes it.

References

This post is part of design patterns guide series. Code examples are located in GitHub for C# and Java.

Example

It might not be a good idea to have the pattern in the name of the facade, but in the example, I’ve put it to ease. In this example, WebDriver instantiation is hardcoded to Firefox, but in real life, it will be instantiated based on some rules. Facade exposes Start, Stop and FindElement methods. All other WebDriver functionality is not accessible.

public class WebDriverFacade
{
	private IWebDriver webDriver = null;
	private TimeSpan waitForElement = TimeSpan.FromSeconds(5);

	public WebDriverFacade()
	{
		webDriver = new FirefoxDriver();
	}

	public void Start(string url)
	{
		webDriver.Url = url;
		webDriver.Navigate();
	}

	public void Stop()
	{
		webDriver.Quit();
	}

	public IWebElement FindElement(By by)
	{
		try
		{
			WebDriverWait wait = new WebDriverWait(webDriver, waitForElement);
			return wait.Until(ExpectedConditions.ElementIsVisible(by));
		}
		catch
		{
			return null;
		}
	}
}

A facade is used exactly the same way as WebDriver itself:

WebDriverFacade webDriver = new WebDriverFacade();
webDriver.Start("https://automationrhapsody.com");

IWebElement logo = webDriver.FindElement(By.CssSelector("div#header-inner h1 a"));
logo.Click();

webDriver.Stop();

Conclusion

WebDriver API is neither complex nor poorly designed, so maybe making a facade is not a mandatory thing. Still, I think having control over its usage is a good approach. In given example, you can see I use explicit wait so I locate exactly the same way all elements in my automation project.

Related Posts

Read more...

Page objects design pattern

Last Updated on by

Post summary: Description of code samples of Page Objects design pattern.

This is the most important pattern related to software automation. It enables you to create object repository with UI elements. Elements are separated from test logic. This pattern makes code much more maintainable and reusable.

References

This post is part of design patterns guide series. Code examples are located in GitHub for C# and Java.

Never do this

Without this pattern what you might do is start WebDriver, navigate to some test page. Locate element you need then click it.

IWebElement element = webDriver.FindElement(By.CssSelector("div.find label"));
element.Click();

This is good when you want to test the idea or do some quick demo. In a real-life project, this element might be needed in dozens of tests. What happens if the UI changes and CSS selector is not matching anymore? Here comes the maintainability problem, you have to search and replace all of them.

The proper way

In software engineering, there is a principle called DRY for short. Its idea is to have each element or action stored only once in a system. This avoids copy/paste and reduces the overhead for code maintenance. The same idea is used in Page Object pattern.

  • Each page or re-usable part of a page (i.e. header, footer, menu) is a separate class.
  • Class constructor takes WebDriver as an argument and uses it internally to locate elements.
  • Each element is a private property (or getter in Java).
  • Actions are public and internally operate with elements.

In the code below SearchField is private property used only by SearchFor method which is exposed to available action on HomePage. An element can be located inside the action method but suggested approach gives better readability. And if an element is needed more than once then defining it separately is a must.

public class HomePage
{
	private IWebDriver webDriver;

	public HomePageObject(IWebDriver webDriver)
	{
		this.webDriver = webDriver;
	}

	private IWebElement SearchField
	{
		get { return webDriver.FindElement(By.Id("search")); }
	}

	public void SearchFor(string text)
	{
		SearchField.SendKeys(text);
	}
}

The page object is instantiated in the test and actions are invoked.

HomePageObject homePage = new HomePageObject(webDriver);
homePage.SearchFor("automation");

With this approach, you have one element defined in only one place. Only actions are exposed out of the page object. It is very clear what actions can be done on this page.

Original page objects

To be honest what I have described in this post is not actually the original Page Objects pattern. Although the idea is same I have modified it slightly. Originally each action returns a page object. In this way, you can chain methods in one test and very easy to understand if a test will be broken when given action now returns different page object. I do not like chaining of methods though so I don’t need this extra. It doesn’t bother you at all to do

public HomePage SearchFor(string text)
{
	SearchField.SendKeys(text);
	return this;
}

Also, I have separated elements located outside of actions because I want better maintainability and readability of the code.

Conclusion

Always use page objects in your test automation. ALWAYS!

Related Posts

Read more...

Design patterns every test automation engineer should know

Last Updated on by

Post summary: Description with examples of 5 design patterns that is good to know and use in our automation testing.

Design patterns are an interesting topic. They are created to solve common problems in software design. Although design patterns are not reserved only for software development they seem not to be widely discussed in software automation. Maybe this is because the topic sounds complicated. Yes, there are really sophisticated design patterns used to solve complex issues in software development. But also there are easy to understand and adopt design patterns that can significantly improve readability and maintainability of our test automation code.

With series of posts, I’m going to give an overview with examples of some design patterns that can be very useful in our test automation projects. To keep blog neat in this first post I’ll just outline the list of patterns. Each one will be discussed in a separate post with code samples.

Page Objects pattern

This is the most important pattern related to software automation. It enables you to create object repository with UI elements. Elements are separated from tests logic. This pattern makes code much more maintainable and reusable. Page objects design pattern

Facade pattern

The whole idea of facade design pattern is to provide simple and easy to use interface to a larger and more complex code, API or set of APIs. Most likely you don’t need everything provided by the API. So for ease and better maintainability, only API features that are needed gets exposed outside the facade. In this way, you simplify the API usage and you have control over how this external API is used and can prevent misunderstanding or misuse. Facade design pattern

Factory pattern

Factory pattern is used to create objects based on specific rules. You may have several classes implementing an interface. In your code, you do not want to bother defining which concrete class to instantiate or you might not know what object is suitable to get instantiated. This is why you handle the object creation task to the factory which knows exactly what object to create. With factory pattern, object creation is encapsulated. Factory design pattern

Singleton pattern

Singleton pattern is needed when you need exactly one object from a specific class in the whole application. Singleton and Null object patterns

Null object pattern

The idea is to make code simpler and safe by skipping null reference checks. Null object implements given interface and its methods are doing nothing. This makes the null object predictable. You can safely invoke methods on the null object without the threat of a NullReferenceException to break your application. Singleton and Null object patterns

Putting all together

Once you have gone through patterns one by one now it is time to put everything into one project. Complete guide how to use design patterns in automation post is showing how.

Related Posts

Read more...