Blog Series: Behavior Driven Development in LEAPWORK
- Chapter 1: BDD - Behavior Driven Development
- Chapter 2: The Page Object Model
- Chapter 3: Unit-testing
- Chapter 4: Context Driven Automation
Concepts such as “Behavior Driven Development (BDD)”, the “Page Object Model”, “Unit-testing”, and “Context Driven Automation” are important for automation.
This blog-series contains four chapters:
BDD is used to include non-technicians in the software development process.
The Page Object Model is used to encapsulate an interface (for example the interactive elements in a webpage).
Unit-testing is used to secure, that changes made to the units (parts of code), will not introduce any unexpected breaking changes.
Context Driven Automation is used to reduce the maintenance cost of automation by 99%.
This blog examines:
BDD is a development method, where a behavior of an application should be written before the application is developed. The behavior of an application is described as testable features in a language called Gherkin.
A feature file consists of a feature description and multiple scenarios, that describes the context of how a feature is supposed to be used or behave.
A scenario is made of steps, that have to start with either:
Given - the preconditions, before the behavior can happen.
When - the actions that trigger the application behavior
Then - the result of the application behavior.
To give a better language flow, “And” and But” can replace multiple “Given”, “When” and “Then” steps:
Will be more readable when written:
Cucumber is the most popular implementation of Gherkin in testing.
Gherkin is much easier to read, than a programming language or cryptic references.
This is not preferable:
Use Gherkin in LEAPWORK?
LEAPWORK with it’s visual building blocks can easily replace the physical programming, but it does not replace the principles in programming, computer science, and software engineering. These principles are needed to deal with the complexity and abstraction of software development. For example, the logical business layer can be separated from the physical business layer.
The logical business layer
The logical business layer is to describe the behavior, without thinking about the implementation:
It is best practice to write the logical business flow in the Gherkin language, because only the essential parameters are present. Combinations for parameters in the visualized case are clear and can be made data driven through a decision-table:
The physical business layer
The physical business layer is to describe the actions required to achieve the behavior:
It is not best practice to write the physical business flow in Gherkin, even though it is doable, because the parameters and purpose get lost in the actions.
The same goes for LEAPWORK, where multiple building blocks can be combined into a sub-flow. These subflows can then be renamed into “Given”, “When”, and “Then” steps and combined together:
Which is a lot more readable and understandable than this example:
Even with zoom it is difficult to guess, what the automation is doing, since the parameters and purpose get lost in the details.
What is a page object?
A web page consists of multiple elements, such as paragraphs, images, input fields, buttons, etc. A page object is a reference to one of these elements.
This reference can for example be a xpath:
//div[@id = “article container”]//button
The xpath can be read as following:
- Select the div tag with the id “article container”
- and inside it select first button inside it:
Why do we need page objects?
Page objects can be assigned meaningful names and it is easier to read a meaningful name such as “acceptButton”, than a cryptic xpath such as //div[@id = “article container”]//button. It is also impossible to guess, that a button with the text “Click me!” is actually an accept button.
Easier to maintain
Page objects also makes it easier to maintain an automation suite. If a button changes or is moved on a web page, then the automation engineer would have to find and update all the xpath references. With a page object, it is only required to update the reference a single time, and it is also easy to locate.
Giving page objects a context
All web page objects could be stored in a single big file, but how should the objects be sorted? Doing it alphabetically would make it easier to find an object in a list of a 1000 objects. What if there are two or more “accept buttons” in a application?
It is a good idea to split all the buttons into multiple pages or screens files, so it is easier to know the difference between two or more accept buttons.
Some buttons might be reused on multiple pages or screens, in for example a global menu, then a global page object could also be created:
Page global menu
This best practice will also make it easier to find the specific buttons, images, input fields etc.
Page objects in LEAPWORK
In LEAPWORK the user don’t need to write any cryptic xpath, but can visually select a page object with the mouse.
But instead of creating a new strategy each time for the same button, image, text, etc, it is best practice to reuse existing one. Naming the strategies is also recommended, because:
It is easier to find and reuse them.
The log will be easier to read, since “accept button couldn’t be found” is again a lot easier to read than “//div[@id = “article container”]//button couldn’t be found”.
It is also best practice to put the strategies into folders (or give them a prefix), based on pages or screens, to differentiate between two similar page objects.
Flow structure to avoid in LEAPWORK:
Best practice flow structure in LEAPWORK:
And the page objects can simply be drag over to a building block:
And you will end up with:
The problem of regression
Automation is not only about execution, but implementation of automation can also be automated.
If two or more LEAPWORK flows use the same logic, it can be a good idea to make a subflow and reuse in all the necessary flows.
The first version of the custom subflow would be put into the first flow and tested multiple times to fix the errors. When the errors are fixed, then the subflow would be put into the next flow and tested again, etc.
When a change is made to the subflow, then it could influence all the flows that are using the subflow. Test Engineers often run their complete testsuite to see, if something have been broken. This is time consuming, since a large test suite can take multiple hours to execute. If an error is found and fixed, then the whole test suite needs to be run again, to see if the fix broken other things.
The time consumption is bad, but there is another problem: Can we still trust the test-automation? Just because all the test cases pass, don’t mean they pass as expected.
Let take an oversimplified example:
A test case is passing, because “some variable” is set to the value 1 in a sub flow:
A refactoring of a sub-flow changes “some variable” value to 2, which will break this test case.
Changing “some variable” back to value 1 in the test case will make the test case pass:
But the test case don’t test anything anymore, because we just compare if 1 equals 1, which will always be true.
So how do we secure we don’t break the validity of our test-automation (or RPA)?
Introduction to unit-testing
All flows using a subflow, are using the subflow in a specific context. This context can be simulated through unit-tests in LEAPWORK.
If I refactor a sub-flow and a single unit-test break, then I will know that my change will break my test-suite. I can try to refactor my sub-flow even more, in order to not break any unit-test and catch 99 % of all the problems, before running my complete test-suite. In case a change do break by test suite, I find out why and add it into my unit-tests, so a change like that will never break my test-suite again.
The best part about unit-testing is, that they are fast compared to my test suite. A single web test can easily take 60 seconds to complete and a complete test suite can take hours. A unit-test will be less than 5 seconds and a complete unit-test suite can take a few minutes.
A unit test example in LEAPWORK
The following subflow:
Can be simplified an “assert.equal” subflow that also can be reused to simplify other subflows:
Best practice would be the following folder structure, where the “support” folder contains all the logic sub-flows and the unit-tests folder replicates the “support” folder containing all the unit-test:
A unit-test would be a standard flow, that can be run, and my assertion.equal subflow would use two unit-test where:
- “actual value” equals “expected value” (a positive unit-test)
Where I test if my assert.equals can pass.
- “actual value” not equals “expected value” (a negative unit-test)
Where I test if assert.equals can fail and give the correct fail message.
The attentive reader would notice, that I actually use my assert.equal to test my assert.equal subflow. I just need to make sure, that I “turn on” unit-testing by setting assertEqual.unitTest to true, because I don’t have a “try” and “catch” command in LEAPWORK, as I would have in other programming languages.
To run my unit-test I would simply, right-click on my unit-test (or the folder I want to unit-test) and select Run >> local agent:
This will generate the following report:
Which gives me impressive low runtime for each unit-test!
The report itself takes ~11 seconds to be generated, so you won’t get results instantly (Maybe LEAPWORK can improve that).
This will help you automate you implementation process, by increasing the implementation speed significantly, but also lower the risk of breaking the validity of your test-automation or RPA.
Complexity is paralyzing, but simplicity is not a solution to complexity, because simplicity is often inadequate. Mohammad El-Wali and I have developed Context Driven Automation to deal with complexity, so instead of reducing the complexity, we split it into multiple layers of context. Let’s take an example:
An enterprise has three web products, that have very similar business processes, but each one has their own audience.
Instead of building a test-automation suite for each web product, we can just make a single one, where the same test case can be executed on the three different web products.
To make it clear, that the web products doesn’t need to be exactly the same, I will show an example where I will reuse the same test case on three completely different sites, but with similar business processes:
In this example Context Driven Automation will take BDD to the next level, by making 3 different page object models and switch between them with a single variable:
This variable could also be an environment variable. Therefore the same scenario stays the same for each web product, so the test- or RPA-designers can focus on what is important, instead of getting lost in details, such as buttons, input fields, menu’s, text-parsing, etc.:
The page object model would be split up in 3 folders:
And in LEAPWORK it should look like this:
Each of the steps will now have 3 different flows (for maps.google.com, for rejseplanen.dk, and for dsb.dk), where the flow is split by a “Switch” building block:
Steps sub-flows examples with switch building blocks
I want to use _
I departure from _
I travel to _
Time is _
My travel time should be _
Reuse of BDD-steps
The BDD-steps “Given”, “When”, “Then”:
can now be used to create multiple test-cases or RPA-flows, that work for 3 different web-products.
IThese steps can also be used for other test-cases and RPA-flows, for example:
By adding multiple other “Given” steps, such as:
In language _ (english or danish)
As a _ (adult, child, retired, etc.)
With browser (Firefox,Chrome, Edge, IE, etc)
And adding multiple “When” steps, such as:
I want only to use _ (trains, busses, etc.)
I want to travel via _ ( 1, 2, 3 extra addresses)
And adding multiple “Then” steps, such as:
My price should be _
Number of transfers should be _
Then these 12 steps (5 original and 7 new) can be combined into:
3 application x 2 languages x 3 age_types x 4 browsers x 2 transport_options x 4 travel_vias x 3 assertions (travel time, price, number of transfers) = 3x2x3x4x2x4x3 = 1728 scenarios
The maintenance would be reduced to 11/1728 = 0,6 %, which is a reduction by 99,4 %. Adding more steps will make a reduction below 99,9 % achievable!
Implementing unit-tests will also reduce implementation-time, since most of the errors will be caught, without running the whole test-suite with selenium. For example, rejseplanen.dk required a ”change-text-method” (see the image below) in the “change text block”, that LEAPWORK doesn’t support (yet), so I had to make my own “substring from the right”:
Which I can unit-test by itself instead instead of by running the whole testsuite.
All the examples can be downloaded here.
The only problem is, that web applications are changing so fast, that my examples might stop working after a week.
Good thing is, that I only would need to update 12 steps, in order to update all 1728 scenarios!