I’ve been helping with test automation for a couple of projects. Every time we start fresh and have all good intentions to keep our regression suite clean. Every time we end up tossing things around and spending the time to adjust our scripts in order to avoid big changes with every little new UI change. Is there an option to reduce the overhead? I know my specs are a representation of original requirements. I also noticed that there is something usability engineers could benefit.
I’ve spent some time analyzing what levels of abstraction we have during automating specifications. I looked at what type of language we use on each of these levels and this is what I found:
Let’s take a look on every level with some more or less practical examples.
I assume you know about behavior driven development, Gherkin language and tools like SpecFlow. Using Gherkin language on this level makes a lot of sense. This level is very much about the business meaning of our product thus it’s valuable if business people can understand this kind of tests. So, let our Gherkin scenarios speak the language Product Owner could understand and use as his own:
Feature: Shopping Scenario: I want to buy a present for Christmas and I don't have any clue what to buy Given I know my budget And I know whom I buy a present When I ask for help to choose a present And I tell about the person I buy a present And I tell my budget Then I'm offered with relevant options
I bet my Product Owner can read the script above and may also find mistakes without any noticeable effort. I even hope he could create scenarios for me so we could help each other and have a point for collaboration.
At this level, I’ll refer to a page object pattern explained by Martin Fowler. The page object pattern helps to separate low-level clicks and objects from more meaningful screens and page blocks that make our product. These screens and blocks are specific to the product. Some teams even create a catalog out of those blocks and reuse them through the product. These blocks usually are tightly coupled with work that usability engineers are doing, and this probably would be a topic for another article — still nothing like an input, button or label. To show an example, I use NOpenPage library- a lightweight implementation for the page object pattern that extends Selenium. The example shows SpecFlow steps:
[Binding]public class MySteps{ [When(@"I ask for help to choose a present")] public void When_I_ask_for_help_to_choose_a_present() { Browser.Do(TheShopPage.Navigate); Browser.On<TheShopPage>().AskForHelpToChooseAPresent(); }
[Then(@"I'm offered with relevant options")] public void Then_Im_offered_with_relevant_options() { Browser.On<TheShopPage>().AssertRelevantOptionsOffered(); }}
This level needs some effort from a person with development skills although the language could be clear for a usability engineer as we speak about pages, blocks on those pages and scenarios. Let’s assume asking for help is something like a wizard. Then method AskForHelpToChooseAPresent could look like this:
public class TheShopPage : Page{ public TheShopPage(IPageContext context) : base(context) { }
public static void Navigate(IWebDriver driver) { driver.Navigate().GoToUrl("https://theshop.it"); }
public void AskForHelpToChooseAPresent(string gender, int age) { Control<Gender>().Choose(gender); Control<Age>().Choose(age); }
public void AssertRelevantOptionsOffered() { Control<Offers>().AssertRelevantOptionsOffered(); }}
So, now this should be clear. We went to the bottom. Buttons, labels, and inputs live here. We put here all Selenium related code inside page objects implemented with NOpenPage:
public class Gender : PageControl{ public Gender(IPageControlContext context) : base(By.ClassName("gender"), context) { }
public void Choose(string gender) { var input = Element.FindElement(By.Id(gender)); input.Click(); }}
By following these three levels of abstraction:
Examples here are very abstract although I only want to show the idea of using business language on top, usability language in the middle and keep low-level technical details at the bottom. This approach helps a lot writing clean code for my automated tests.
Happy coding,Michael Borisov
Originally published at corker.github.io on March 4, 2017.