As a software engineer, We all face some errors/exceptions while writing code! So what do we do when we face such a problem? If we are not sure, We google for solutions immediately. Don’t we? We google because we know that we would not be alone and someone would have already found the solution, for the problem we are facing now, which we could use to solve our problem.
Well, What to do if we face an issue in the high level software design – when connecting different classes / modules – when you have only a vague idea!! How can we google such things when we ourselves are not sure of the problem we have in the first place!!
No worries, You still have a solution!
Design patterns are the solutions for the problems which you might face in the software design!!
Design Patterns are well optimized and reusable solutions to a given problem in the software design. It helps us to show the relationship among the classes and the way in which they interact. Design pattern is a template which you have to carefully analyze and use it in appropriate places.
Design Patterns in Test Automation:
As an automated test engineer, should we really care about design principles and patterns? Why do we need to learn/use Design Patterns in functional test automation?
After all, Test automation framework/automated test case is also a software which is used to test another software. So, we could apply the same design principles/patterns in our test automation design as well to come up with more elegant solution for any given design related problem in the test automation framework.
Remember that Design Patterns are NOT really mandatory. So you do not have to use them! But when you learn them, you would know exactly when to use! Basically these are all well tested solutions. So when you come across a problem while designing your framework/automated test cases, these design patterns could immediately help you by proving you a formula / template & saves us a lot of time and effort.
Strategy Pattern:
Goal: Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from the clients that use it.
That is, Strategy Pattern is useful when we have multiple algorithms for specific task and we want our application to be flexible to choose any of the algorithms at run time for specific task.
Still confused? No Worries!
Lets take Google application as always we do.
We could search with simple keywords by typing in the text box. Or We could say few keywords using voice search. In both cases, Google does the search and shows us the results.
So, Google has implementations for 2 different strategies to get the input from user. As a user, it is up to you to choose the search method – either voice search or text search. Then Google uses appropriate strategy to collect the keywords and send it to its engine to fetch the results.
Yet another example, Lets assume in your test framework, you want to create some custom reporting utility. You want this utility to create the report in any of these HTML/JSON/XML/CSV formats. You should have a strategy for each format. Then you choose the strategy for the format you need to create the report.
If you find any other similar requirement, Strategy Pattern will be extremely useful there.
Strategy Pattern in Google Page object:
We are going to create a Google Page object and we will use these different strategies for the search. We do not want the Page object to do any search. Instead, It will contain an object which is implementing the interface ‘SearchStrategy’. Google page class will delegate the search work to the object.
SearchStrategy:
public interface SearchStrategy { void setDriver(WebDriver driver); void search(String searchFor); }Text Strategy:
public class TextStrategy implements SearchStrategy { private WebDriver driver; private By searchBox = By.name("q"); private By searchButton = By.name("btnG"); public void search(String searchFor) { System.out.println("Searching using Text Straegy:" + searchFor); driver.findElement(searchBox).sendKeys(searchFor); driver.findElement(searchButton).click(); } public void setDriver(WebDriver driver) { this.driver = driver; } }Google Page Object:
public class GooglePage { private WebDriver driver; private SearchStrategy strategy; private By result = By.className("rc"); public GooglePage(WebDriver driver, SearchStrategy stragey) { this.driver = driver; this.strategy = stragey; this.strategy.setDriver(driver); //navigate to google page driver.get("https://www.google.com"); } public void search(String txt) { this.strategy.search(txt); } public int getResultsCount() { return this.driver.findElements(result).size(); } }Strategy Pattern Test:
public class StrategyPatternTest { DriverManager driverManager; WebDriver driver; @BeforeTest public void beforeTest() { driverManager = DriverManagerFactory.getManager(DriverType.CHROME); } @BeforeMethod public void beforeMethod() { driver = driverManager.getDriver(); } @AfterMethod public void afterMethod() { driverManager.quitDriver(); } @Test(dataProvider = "dp") public void googleSearchStrategy(SearchStrategy strategy, String searchString, int resultCount) { GooglePage google = new GooglePage(driver, strategy); google.search(searchString); Assert.assertEquals(resultCount, google.getResultsCount()); } @DataProvider public Object[][] dp() { return new Object[][] { new Object[] { new TextStrategy(), "Test Automation Guru", 7 }, new Object[] { new TextStrategy(), "Selenium WebDriver", 14 }, }; } }Summary:
By using Strategy Pattern, we completely hide the search algorithm in the Google page class. Test classes choose the search method they want. In future, If we need to add different Search Strategy, you need to create a new class implementing the interface. You do not modify any existing classes you have created already which is cool. If we touch a working code for modification, there is a chance that we introduce a new defect!! By using composition, Google page simply delegates the search work and make the Google page class very flexible.
Design Pattern is a very good tool for effective communication. How? As soon as we name a pattern, Others can immediately picture the high-level-design in their heads & get the solution for the given problem. Thus, Design Pattern enables us to explain the design in a much better way.
You might be interested in other best practice examples. Check below articles to learn more!