Test Automation Engineering
Test Automation Engineering
Handbook
Manikandan Sambamurthy
BIRMINGHAM—MUMBAI
Test Automation Engineering Handbook
Copyright © 2023 Packt Publishing
All rights reserved. No part of this book may be reproduced, stored in a retrieval system, or transmitted
in any form or by any means, without the prior written permission of the publisher, except in the case
of brief quotations embedded in critical articles or reviews.
Every eort has been made in the preparation of this book to ensure the accuracy of the information
presented. However, the information contained in this book is sold without warranty, either express
or implied. Neither the author(s), nor Packt Publishing or its dealers and distributors, will be held
liable for any damages caused or alleged to have been caused directly or indirectly by this book.
Packt Publishing has endeavored to provide trademark information about all of the companies and
products mentioned in this book by the appropriate use of capitals. However, Packt Publishing cannot
guarantee the accuracy of this information.
ISBN 978-1-80461-549-2
www.packt.com
To my late mother, Gomathy, whose unconditional love inspires me to always do my best. To my dad,
wife, children, and sisters, whose support gives me the condence to complete this work.
– Manikandan Sambamurthy
Contributors
I would like to thank my wife and two children, who have supported me throughout the process of
writing this book. Sincere thanks to the tremendously helpful team at Packt for getting this book to
completion. I would also like to thank the technical reviewers for all their valuable feedback.
About the reviewers
Ayesha Janvekar is an IT professional based in San Diego, California. She is currently working as
a soware development manager with more than 9 years of hands-on QA experience. Ayesha is an
experienced IT leader and is passionate about soware testing. She has a bachelor’s degree in electronics
and communication engineering, an MBA in marketing and international business, and a master’s
in information technology and management from Chicago. She believes in translating her work into
actionable insights. Having strong project management skills and business acumen, Ayesha helps
deliver pragmatic technical solutions.
Meir Blachman, an Israeli Jew, completed a bachelor’s degree in computer science aer high school.
In 2014, he joined the Israeli army and served in the 8200 unit for 5.5 years. Meir started his service
as an automation engineer and introducing teams to web automation, and transitioned to backend
engineering focusing on CI/CD tooling and automation around the development team components. In
2019, he started working for Microso on the Cloud App Security group, specically on the Conditional
Access App Control product. During this time, Meir learned how the web works, and specically
browsers, involving the HTML, CSS, and JavaScript standards and how browsers process this content.
He has also invented multiple patents through Microso.
Chris Wallander is the principal SDET and test automation architect at TaxAct and has over 10 years
of experience in test automation and quality assurance, as well as a solid foundation in DevOps and
Agile methodologies. Trained and certied through the International Soware Testing Qualication
Board, his focus is on analyzing enterprise systems, and then building test automation frameworks to
support them. Outside of work, he enjoys developing and testing video games, AI/ML development,
building robots, and smithing medieval armor.
Table of Contents
Preface xiii
2
Test Automation Strategy 21
Technical requirements 21 Test automation environment 24
Knowing your test Implementing an Agile
automation strategy 22 test automation strategy 26
Reporting the test results 28
Test automation objectives 22
Gathering management support 23 Devising a good test
Dening the scope of test automation 24 automation strategy 29
viii Table of Contents
Selecting the right tools and training 29 Structuring the test cycles 37
Standards of the test automation framework 30
Familiarizing ourselves with
Testing in the cloud 34
common design patterns 37
Understanding the test pyramid 35 Using design patterns in test automation 37
Unit/component tests 35
Summary 42
Integration/API tests 36
E2E/System/UI tests 36
Questions 42
3
Common Tools and Frameworks 43
Technical requirements 43 JMeter 63
e basic tools for every AXE 65
automation engineer 43 Choosing the right tool/framework 66
e CLI 44 Selecting a performance testing tool 66
Git 49 Selecting an API testing tool 67
Common test automation Selecting a web testing tool 67
frameworks 56 Mobile 68
Selenium 57 Common considerations 68
Appium 60 Summary 69
Cypress 62 Questions 69
5
Test Automation for Web 103
Technical requirements 103 Working with selectors 116
Why Cypress? 104 Asserting on selectors 117
6
Test Automation for Mobile 125
Technical requirements 125 Writing our rst mobile test 138
Getting to know Appium 126 JavaScript functions with async/await 138
What is Appium? 126 First Appium/WebdriverIO test 140
Advantages of using Appium 126 Key considerations for mobile
Knowing WebdriverIO and automation 141
its advantages 127 Areas of complexity 141
Setting up Appium and iOS-specic considerations 142
WebdriverIO 127 Optimizing our mobile
Appium installation 127 automation framework 144
Conguring an Android emulator 129 Summary 146
Conguring WebdriverIO with Appium 132
Questions 146
WebdriverIO Android conguration 134
Appium Inspector installation
and conguration 136
x Table of Contents
7
Test Automation for APIs 147
Technical requirements 148 Using snippets for asserting an API response 162
Getting started with Postman 148 Understanding Postman variables 164
Chaining API requests 166
Basics of REST API testing 148
Various ways to execute tests 167
Downloading the Postman application 149
Creating and managing workspaces 150 Key considerations for API
Sending GET and POST requests 151 automation 171
Eective API test automation 171
Making a GET API request 152
Testing GraphQL versus REST APIs 172
Making a POST API request 155
Organizing API requests using collections 157 Summary 172
Writing automated API tests 162 Questions 173
8
Test Automation for Performance 175
Technical requirements 175 Java essentials for JMeter 190
Getting started with JMeter 175 A quick introduction to Java 191
What is JMeter and how does it work? 176 Using the JSR233 assertion 193
Installing JMeter 176 Considerations for
Automating a performance test 179 performance testing 195
Building and running our rst Summary 196
performance test 179 Questions 196
Working with assertions 184
Working with tests via the command line 186
Using the HTTP(S) Test Script Recorder 189
Table of Contents xi
10
Common Issues and Pitfalls 213
Recurrent issues in test automation 213 Not taking a lean approach 216
Unrealistic expectations of automated testing 213 Not having a plan for test data needs 217
Inadequate manual testing 214 Test automation anti-patterns 217
Not focusing on automating the right things 214
Coding and design anti-patterns
A lack of understanding of in test automation 217
the system under test 215
Process-oriented anti-patterns
Overlooking test maintenance 215 in test automation 223
Not choosing the right tools 215
Under-investing in test environments 216 Summary 226
Taking a siloed approach 216 Questions 227
Assessments 235
Chapter 1, Introduction Chapter 6, Test Automation
to Test Automation 235 for Mobile 238
Chapter 2, Test Automation Strategy 235 Chapter 7, Test Automation for APIs 238
Chapter 3, Common Tools Chapter 8, Test Automation
and Frameworks 236 for Performance 239
Chapter 4, Getting Started with Chapter 9, CI/CD and Test
the Basics 237 Automation 239
Chapter 5, Test Automation for Web 237 Chapter 10, Common Issues
and Pitfalls 240
Index 243
soware engineers, and manual testers can gain practical insights throughout this book. Let’s see how
this book helps each role:
• Quality engineers: Quality engineers who have a test automation foundation but are seeking
to upskill in test automation across various platforms will learn relevant knowledge. ey will
also get a deeper grasp of test automation strategies and considerations. It can also act as a
supplement for quality engineering interviews.
• Manual testers: Manual testers who wish to switch over to test automation engineering roles
can use this book as the foundation and guide for their journey.
• Soware engineers: Soware engineers who would like to get quickly up and running with a
test automation framework can use this book as a guide. It will not only help familiarize with
a framework but also review the additional considerations needed when adopting it.
Chapter 8, Test Automation for Performance, introduces readers to the JMeter tool and explains how
to create and execute performance tests using it. It explores the various useful aspects of JMeter for
building a complete performance test. It also reviews certain key considerations when designing
performance tests.
Chapter 9, CI/CD and Test Automation, establishes the concepts of CI/CD and deals with how test
automation strategies apply to the CI/CD methodology. It also takes readers through a demo of GitHub
Actions, which is a built-in CI/CD tool in GitHub.
Chapter 10, Common Issues and Pitfalls, educates readers on some of the common issues faced in test
automation and recommends a solution for each of them. It also provides tips on avoiding any pitfalls
when implementing test automation projects.
Appendix A, How to Dockerize Automated Tests, helps readers to use container technology to build
and run automated tests.
Conventions used
ere are a number of text conventions used throughout this book.
Code in text: Indicates code in action, commands, keywords, folder names, lenames, le
extensions, and pathnames.
Here is an example: e setTimeout() function calls a method aer a specied wait in milliseconds.
For example, setTimeout(() => console.log(hello!), 5000) prints the message
aer a wait of 5 seconds.”
A block of code is set as follows:
Bold: Indicates a new term, an important word, or words that you see onscreen. Here is an example:
Use the Settings option in the Preferences menu for additional conguration.”
Get in touch
Feedback from our readers is always welcome.
General feedback: If you have questions about any aspect of this book, email us at customercare@
packtpub.com and mention the book title in the subject of your message.
Preface xvii
Errata: Although we have taken every care to ensure the accuracy of our content, mistakes do happen.
If you have found a mistake in this book, we would be grateful if you would report this to us. Please
visit www.packtpub.com/support/errata and ll in the form.
Piracy: If you come across any illegal copies of our works in any form on the internet, we would
be grateful if you would provide us with the location address or website name. Please contact us at
[email protected] with a link to the material.
If you are interested in becoming an author: If there is a topic that you have expertise in and you
are interested in either writing or contributing to a book, please visit authors.packtpub.com.
https://packt.link/free-ebook/9781804615492
In this part, we will begin with the basics of testing and test automation. You will learn about the
considerations that go into devising eective test automation strategies. You will also get familiarized
with Git and grasp the fundamentals of prominent test automation frameworks. By the end of this
section, you will recognize and understand commonly used test automation terms, frameworks, and
tools.
is part has the following chapters:
Soware testing is an indispensable task in any soware development project that is mainly done
with the goals of validating the specied product requirements and nding bugs. ese bugs can
be functional or non-functional in nature. Functional bugs include deviations from the specied
requirements or product specications. Usually, non-functional issues are performance-based or
security-based. e primary goals of testing are usually interwoven at multiple levels but can be
broken down at a high level as follows:
• Non-functional: Checking the non-functional aspects of the soware system, which are never
tackled by functional testing:
Now that we have seen a quick introduction to testing, let us understand why testing is so critical.
• Review of the test plan with the engineering and product teams
• Cross-team collaboration for the test environment setup
• Creation of test cases and test data
• Execution of test cases
• Reporting of test results and associated quality metrics
Depending on the team size, capacity, and structure, some or all of these activities must be performed
for a successful release of a soware product.
In the following diagram, we get a comprehensive view of all the deliverables involved in soware testing:
As you can see in the preceding diagram, testing encompasses a wide variety of deliverables resulting
from many cross-functional activities. Next, let’s look at some unique demands for testing in the world.
Testing in an world
Unlike a traditional waterfall model, in the Agile world, it is recommended that each user story or
feature has the right balance of manual and automated tests before calling it done. is arguably slows
down the team, but it also drastically reduces the technical debt and improves code quality. You will
notice that scaling the soware becomes easy, and there is a signicant decrease in reworking as the
automated tests increase. is saves huge amounts of time for the engineering team in the long run.
Another common occurrence in an Agile setup is developers writing automated tests. Usually, developers
own unit tests, and quality engineers write other types of tests. Sometimes, it is productive for the
developers to write automated test code while the quality engineers focus on other testing tasks. One
of the most important takeaways from the Agile world is that quality is everyone’s responsibility on
the team. Test engineers keep the communication and feedback going constantly between the product
6 Introduction to Test Automation
and the soware engineers, which, in turn, results in an excellent team culture. is also opens up
early discussions on the necessary tools and infrastructure needed for testing.
Since the Agile environment aims to deliver the simplest possible product to the customer as quickly
as possible, the test engineers focus on the most necessary set of test cases for that product to be
functionally correct. In each increment, the test engineers create and execute a basic set of test cases for
the features being delivered to the customer. Test engineers are constantly working with the product,
developers, and in some cases, with customers to keep the stories as simple and concise as feasible.
Additionally, the Agile landscape opens doors to automating the entire soware development life
cycle using the principles of continuous integration, which demands a major shi in the test engineer’s
mindset. is demands excellent communication skills and uent collaboration from the test engineers.
Oen, a test engineer’s output is measured by the number and quality of defects they nd in the
soware application. Let us examine some key aspects of defect management next.
Besides the number of bugs being identied, it is also crucial to know when a defect is identied in
the project. Next, let’s explore the eects of shiing testing early or late in the development life cycle.
Getting familiar with software testing 7
Challenges in testing
Before diving into the world of test automation, it is vital to understand the common challenges faced
in the testing world. Building a solid manual testing foundation is paramount to developing a sound
test automation strategy. A clear and concise testing process acts as a strong pillar for building reliable
automation scripts. Some of the challenges faced regularly by the testing team are outlined as follows:
• e most common challenge faced by Agile teams is the changing requirements. Various reasons
such as late feedback from customers or design challenges lead to a change in the requirements
and cause major rework for test engineers.
• Test engineers are required to interface constantly with the various teams to get the job done.
e lack of proper communication here could lead to major blockers for the project.
• Having stories or requirements with incomplete information is another area that test engineers
struggle to cope with. ey constantly have to reach out to products for additional information,
which causes a lot of back and forth.
• Not having the right technical skills for performing all kinds of testing required for a feature
poses a great challenge for test engineers.
• e lack of quality-related metrics hurts fast-growing teams where the velocity is expected
to increase with the team size. e engineering team will be imperceptive to any patterns in
code issues.
• Inadequate test environments are a major bottleneck to testing eorts and directly aect the
condence in the product delivery. e lack of diverse test data in the test environment leads
to an inadequately tested product.
• e absence of standard test processes increases both the development and testing times,
thereby delaying the project timelines. It is good to be cautious about partially implemented
test processes as they, sometimes, hurt more than they help.
Next, let’s look at how testing early and oen helps overcome some of the obstacles in the testing journey.
e following excerpt highlights the cost of xing bugs later in the product development cycle. As Kent
Beck explains in his book, Extreme Programming Explained, Most defects end up costing more than it
would have cost to prevent them. Defects are expensive when they occur, both the direct costs of xing the
defects and the indirect costs because of damaged relationships, lost business, and lost development time.”
e common arguments for not testing early are We don’t have the resources” or We don’t have enough
time.” Both of these are results of not examining the risks of the project thoroughly. It is a proven fact
that the total amount of eort is greater when testing is introduced later on in the project. On the
tester’s part, it is important to reduce redundancy and constantly think about increasing the eciency
of their tests. Test-Driven-Design (TDD) is a common approach to practice Test Early, Test Oen.
Testing processes have to be ne-tuned and adhered to strictly for this approach to be successful.
Testing can have a strategic impact on the quality of the product if introduced early and done oen
and eciently. e Agile test pyramid (which is discussed, in detail, in Chapter 2) can act as a guide
to strategically categorize and set up dierent types of tests.
So far, we have dealt with a range of concepts that help us acquire a well-rounded knowledge of
testing. We looked at the importance of testing and how crucial it is to integrate it with every facet
of the soware development process. With this background, let us take on the primary topic of this
book, test automation.
Testing is denitely not a one-time activity and must be done any time and every time a change is
introduced into the soware application. e longer we go without testing an application, the higher
the chances of failure. So, continuous testing is not an option but an absolute necessity in today’s Agile
soware engineering landscape. Manual testing involves a tester executing the predened test cases
against the system under test as a real user would. Automated testing involves the same tests to be run
by a script, thereby saving the tester’s valuable time so that they can focus on usability or exploratory
testing. When done right, automated tests are more reliable than a manual tester. More importantly,
it provides more time for the tester to draw valuable insights from the results of the automated tests,
which further aids in increasing the test coverage of the soware application as a whole.
Test automation is one of the chief ways to set up and achieve quality in an orderly fashion. e core
benet of test automation lies in identifying soware bugs and xing them as early and as close as
possible to the developer’s coding environment. is helps subdue the damaging eects of late defect
detection and also keeps the feedback cycle going between the engineering and product teams. Even
though the upfront investment in automated tests might seem large, analysis has shown that, over time,
it pays for itself. Test automation enables teams to deliver new features quickly as well as with superior
quality. Figure 1.2 shows how various components of a soware application can be interdependent,
and continuously testing each of them asserts their behavior. It is not only necessary to validate these
components as a standalone but also as an integrated system:
Imagine a simple loan application ow created by a combination of three Application Programming
Interfaces (APIs). e individual APIs, in this case, could be as follows:
Each of the APIs has to be tested in an isolated manner at rst to validate the accuracy of the business
functionality. Later when the APIs are integrated, the business workow should be tested to conrm
the system behavior. Here, a test automation suite can be built to automate both the test cases for
individual APIs and the whole system behavior. Also, when the applicant creation API is reused in
Understanding test automation 11
another application, the automation suite can be reused, thus enabling reusability and portability in
testing. A similar implementation can be done for user interface components, too.
Test automation is a very collaborative activity involving the commitment of business analysts, soware
engineers, and quality engineers/soware development engineer in test (SDET). It unburdens the
whole team from the overwhelming eects of repetitive manual tests, thus enabling the achievement
of quality at speed. While peer code reviews and internal design reviews act as supplemental activities
to identify defects early, test automation places the team in a fairly good place to start testing the
product with the end users. It is a common misconception that automated tests undercut human
interaction with the system under test. While it might be true that the tester does not interact with
the system as oen as they would in manual testing, the very activity of developing and maintaining
the automated tests brings together the whole team by commenting on the test code and design.
Automated tests open a new way of communication within the team to improve the quality of the
system and the prevention of bugs.
Having looked at the basics of test automation, let’s learn some important considerations in the Agile
world.
• Start small and build iteratively on the automated test scripts. is applies to both functional
test coverage and the complexity of the test automation framework.
• Be extremely cautious about what tests are selected for automation. ese tests will act as a
gate to production deployment. Make every eort to avoid false positives and false negatives.
• Make sure the automated tests are considered when deciding on the acceptance criteria for
a feature or a story. It is critical to allocate necessary time and resources for completing and
executing the automated tests as part of a feature.
• Get frequent feedback from other engineers on the quality and performance of the
automated tests.
• Do not be afraid to adapt and change test automation. Constant innovation and improvement
are core activities in an Agile environment.
12 Introduction to Test Automation
As we have seen so far, test automation is an intricate pursuit. Like all other complex things in the
soware world, test automation comes with its own set of challenges. Let’s examine some of them in
the next section.
• As mentioned earlier, not having enough test automation is always a challenge in the Agile
world. Oen, testers have to compromise coverage for speed, and at times, the consequence
can be adverse.
• Not enough planning before beginning test automation work oen leads to duplication and
exhaustion.
• Upfront investment in test automation is heavy, and the constant need to convince the stakeholders
of the benets puts a lot of pressure on testing teams.
• e lack of collaboration between developers and test engineers while designing and developing
automated tests could lead to poor-quality scripts or complicated frameworks. is aects the
quality of the build pipeline.
• e absence of skilled test engineers has a detrimental eect on quality.
• Not aligning the testing processes with the development processes could cause release delays. It
is extremely important to time the code completion of the feature with automated test readiness
for on-time delivery.
• Sometimes, test engineers do not understand the requirements and assume the expected
behavior instead of validating it with the product. It is extremely hard to identify and eliminate
such assertions in the test script aer they have been built in.
• e test automation framework is not scalable or portable. is hinders the execution speed
and results in a lack of test coverage.
Creating and maintaining the test automation infrastructure is a separate project by itself. Every bit
of detail should be thought about and discussed in detail with the concerned stakeholders to address
these challenges.
Understanding test automation 13
Test engineers can be a key component to break the pattern of regression issues and steer the quality
of the product in the right direction by keeping everyone on the team informed. In the next section,
let’s survey some of the top metrics used in the test automation world.
• Test automation eectiveness: is is a key metric that provides visibility into how eective the
automated tests are in nding bugs. When broken down logically by scripts/test environments,
this metric gives direction on where to focus our future eorts:
Test Automation Effectiveness = (# of defects found by automation/
Total number of defects found) * 100
14 Introduction to Test Automation
• Test automation coverage: is metric provides the test coverage for the automated tests. It
is important to be aware of what is not covered by your test automation suite to clearly direct
the manual testing eorts:
Test Automation Coverage = (# of test cases automated/Total
number of test cases) * 100
• Test automation stability: is metric provides clarity on how well the automated scripts
are performing in the long run. is metric, along with test automation eectiveness, is a
key indicator of how aky the automated tests are. It is good to have this metric in an Agile
environment to monitor the health of the deployment pipelines:
Test Automation Stability = (# of test failures/Total number
of test runs) * 100
• Test automation success or failure rate: is metric provides a quick idea of the health of the
current build. In the long term, this metric gives you a good view of how the build qualities
have changed:
Test Automation Success Rate = (# of test cases passed/Total
number of test cases run) * 100
• Equivalent manual test eort: is metric, usually expressed in man hours, is an indicator of
the ROI to determine whether a particular feature can be automated or not:
Equivalent Manual test Effort = Effort to test a specific feature
* Number of times a feature is tested in a test cycle
• Test automation execution time: As the name indicates, this metric shows you how long or
short your test runs are. Comparing this with the overall deployment times to production gives
a good idea of how much time is spent executing the automated tests over time. is is key in
the Agile setup where the speed to the customer is considered a key factor:
Test Automation Execution Time = Test Automation End Time - Test
Automation Start Time
An important note regarding test automation metrics is that these numbers, by themselves, do not
produce much value. A combination of these metrics properly assessed in the context of project
delivery provides valuable insights to the product and engineering teams.
So far, we have seen how testing and test automation blend well with every activity in the soware
development life cycle. It is evident that test automation is a multidimensional undertaking, and the
people performing test automation have to meet the needs of this demanding role. In the next section,
let’s survey a couple of important roles in the quality engineering space.
Exploring the roles in quality engineering 15
e traditional manual tester role is not as prevalent as it used to be, as every role in quality is expected
to perform some level of test automation in the Agile world. So, here, we will be focusing only on
the latter two. is does not mean that manual testing is not done anymore. e responsibilities of a
manual tester are shared by test engineers, SDETs, business analysts, and product owners/managers.
ere are organizations where soware engineers/developers perform their own testing. e engineer
developing the feature is responsible for performing the required testing and delivering a high-quality
product. Oen, small- to mid-sized companies use this approach when they are still not able to build
a separate quality organization or hire test engineers. An important downside of this is that there is a
lot of context-switching that needs to be done by the developers. Also, consistently maintaining the
test coverage at high levels becomes a challenge. A single developer will be focused on providing good
coverage for their own feature, and it is very easy to miss the integration or system-level tests needed
for a business workow. Some developers, plain and simple, do not like to perform tests other than
unit tests due to the tedious and repetitive nature of testing. It is also hard to keep track of the various
details involved in testing dierent parts of an application.
Next, we will look at the most common testing roles that are prevalent in the market.
• Test planning and test strategy development for testing product features (both manual and
automated)
• Preparation of test cases and test data
• Setting up the test environment (usually with help from other engineers)
• Create, execute, and maintain automated tests for the product features
16 Introduction to Test Automation
• Uses the existing test automation infrastructure to build a sound test automation strategy
• Collaborate with product and implementation teams to achieve good test coverage
• Reporting and retesting of bugs
• Coordinating bug xes across teams if necessary
• Streamline test processes
To sum it up, on a daily basis, test engineers have to partner with most of the members of the team
and stay on top of the user stories. ey take ownership of the product quality of the team they are
embedded into. Next, let’s see how an SDET is dierent from a test automation engineer.
SDET
An ideal candidate for the SDET position exhibits sound technical skills and a deep expertise in testing
methodologies. For all practical purposes, technically, an SDET is as good as a soware engineer
with extensive knowledge of the quality engineering space. An SDET will be involved throughout the
development life cycle from unit test creation to production release validation and always strives to
enhance the productivity of both the soware engineer and quality engineer in the team.
e main responsibilities of an SDET include the following:
Table 1.2 highlights the dierences between a test automation engineer and an SDET:
Familiarizing yourself with common terminologies and denitions 17
Even though their roles demand dierent responsibilities, both the quality engineers and SDET are
equally accountable for the release of a bug-free product to the customer. Both should be in the meetings
with product stakeholders to make a nal decision on every feature release. A quality engineer is good
at test case creation, while an SDET specializes in choosing the right ones to automate in the best
possible way. ere are times when quality engineers and SDETs have to work in tandem to keep the
upper management informed and educated about the capabilities of test automation and the eort it
takes to achieve the ROI. Also, it is important to note that the relationship between soware engineers
and quality engineers/SDETs is of utmost importance to the success of any test automation work. It
is vital to get continuous feedback from soware engineers on the test automation code and design.
Soware engineers should also be educated, when necessary, about the various benets derived from
test automation
In the next section, let’s get ourselves familiarized with some commonly used denitions in the world
of testing and test automation.
• A/B testing: Testing to compare two versions of a web page for performance and/or usability
to decide which one better engages the end users.
• Acceptance testing: A testing technique to establish whether a feature/product meets the
acceptance criteria of business users or end users.
• Agile methodology: is is an iterative approach to soware development that puts collaboration
and communication at the forefront. Essentially, it is a set of ideas to deliver soware to
customers quickly and eciently.
18 Introduction to Test Automation
• Test plan: is is a document that outlines a methodical approach to testing a soware
application. It provides a detailed perspective on testing the various parts of the application
in its parts and as a whole.
• Test-Driven Development (TDD): is is an approach mainly used in the Agile world where
a test is written rst followed by just enough code to fulll the test. e refactoring of the code
continues to follow the tests, thus keeping the emphasis on specications.
• Test suite/test automation suite: A collection of automated test scripts and associated
dependencies used to run against the soware application.
• Unit testing: A type of testing in which the logic of the smallest components or objects of soware
is tested. is is predominantly the rst type of testing performed in the development life cycle.
• Usability testing: is is a testing technique used to evaluate a product (usually, a web application)
with the aim of assessing the diculties in using the product.
• Validation: is is the process of ensuring the input and output parameters of a product. It
answers this question: Are we building the product correctly?
• Verication: is is the process of checking whether the product fullls the specied requirements.
Verications answer question: Are we building the right product?
• Waterfall model: is is a project management methodology in which the soware development
life cycle is divided into multiple phases, and each phase is executed in a sequential order.
• White-box testing: A testing technique to validate the features of a product through low-level
design and implementation.
We have equipped ourselves with the knowledge of a wide array of terms used in the quality industry.
Now, let’s quickly summarize what we have seen in this chapter.
Summary
In this chapter, we looked at the importance of testing and test automation. We dealt with some
practical guidance on how test automation interfaces with dierent teams and all the members of the
engineering team. Additionally, we looked at the roles in the test automation world and their specics
and similarities. We understood how test automation helps achieve quality at every stage of the product
development life cycle. Finally, we looked at the dierent terminologies used in test automation.
In the next chapter, we will examine what a thorough test automation strategy entails and how to
dene one. Additionally, we will review a few common test automation design patterns.
20 Introduction to Test Automation
Questions
Take a look at the following questions to test your knowledge of the concepts learned in this chapter:
Technical requirements
In the later part of this chapter, we will be looking at some Python code to understand a simple
implementation of design patterns. You can refer to the following GitHub URL for the code in the
chapter: https://github.com/PacktPublishing/B19046_Test-Automation-
Engineering-Handbook/blob/main/src/test/design_patterns_factory.py.
is Python code is provided mainly for understanding the design patterns and the readers don't
have to execute the code. But if you are interested, here is the necessary information to get it working
on your machine. First, readers will need an integrated development environment (IDE) to work
through the code. Visual Studio Code (VS Code) is an excellent editor with wide support for a variety
of programming languages.
22 Test Automation Strategy
e following URL provides a good overview for using Python with VS Code:
https://code.visualstudio.com/docs/languages/python
You will need soware versions Python 3.5+ and the Java Runtime Environment (JRE) 1.8+ installed
on your machine to be able to execute this code. pip is the package installer for Python, and I would
recommend installing it using https://pip.pypa.io/en/stable/installation/.
Once you have PIP installed, you can use the pip install -U selenium command to install
Selenium Python bindings.
Next is to have the driver installed for your browsers. You can do this by going to the following links
for your particular browser:
• Chrome: https://chromedriver.chromium.org/downloads
• Firefox: https://github.com/mozilla/geckodriver/releases
• Edge: https://developer.microsoft.com/en-us/microsoft-edge/tools/
webdriver/
Make sure the driver executables are in your PATH environment variable.
• Strengthening product quality: is is a chief trigger for test automation projects. Test
automation engineers can plan and create tests that can catch regression bugs and can help
with defect prevention.
• Improving test coverage: is is a key motivation for several test automation undertakings. Test
engineers usually work with the soware engineers and the product team to cover all possible
scenarios. e scenarios can then be categorized based on their criticality.
Knowing your test automation strategy 23
• Reducing manual testing: Needless to say, reducing manual testing is a primary objective for
most—if not all—test automation initiatives. Automated tests are predictable and perform the
programmed tasks in a consistent and error-free manner. is leaves more time for the whole
team to focus on other important tasks, and it boosts the overall productivity of the team.
• Minimizing maintenance and increasing portability of tests: is can be an incredibly
good reason for kicking o a test automation initiative. Legacy soware projects can be ripe
with tightly coupled tests that are not compatible with newer technologies. It usually requires
considerable eort from the testing team to make them portable and easy to read.
• Enhancing the stability of a soware product: is acts as a principal motivation to kick start
a test automation project to address non-functional shortcomings. is involves identifying and
documenting various real-life stress- and load-testing scenarios for the application under test.
Subsequently, with the help of the right tools, the application can be subject to performance
testing.
• Reducing quality costs: is can help the management invest their resources and funds to
further the capabilities of the organization. Reducing redundancy in quality-related eorts helps
trim testing costs and time. Test automation strategy can be a great driver for this endeavor.
A push for test automation can be due to one or a combination of these reasons. Well-thought-out
objectives for test automation eventually increase the overall eciency of the engineering team, thereby
aligning their eorts toward achieving greater business value.
Next, let us look at how important it is to garner management support to achieve the objectives of
test automation.
It is unrealistic to plan to automate every part of a soware application. Every product is unique, and
there is no absolute path to determine the scope of test automation. Planning upfront and constant
collaboration between test engineers, soware engineers, and product owners help lay out the scope
initially. Starting small and building iteratively assists in this approach. It is also crucial to distinguish
upfront which types of testing will be done and by who.
Let us now investigate the crucial role that the test environment plays in a test automation strategy.
e infrastructure team usually makes a replica of the code base and deploys it on dierent virtual
machines (VMs) with the associated dependencies. ey provide access to these VMs for the required
users. Users can then log on to these and perform a series of operations based on their roles and
permissions. e combination of the hardware, soware, and state of these code bases makes it a
separate test environment.
Knowing your test automation strategy 25
• Development
• Testing
• Staging
• Production
We will not be going into the details of each type here, but it is important to keep in mind that the
testing environment is where most of the automated tests are run. e staging environment is usually
used for end-to-end (E2E) testing and user acceptance testing (UAT). is can be both manual
and automated. All organizations have a development environment, but depending on the size and
capacity, some may combine the testing and staging environments into one. Now that we know what
constitutes a test environment, let us look at how to provision one.
A key factor that determines the stability of automated tests is the test environment. Serious considerations
must be made in the setup and maintenance of test environments. is is where the test engineers
must collaborate eectively with the infrastructure teams and identify the limitations of their tests
in the context of a test environment. is analysis, if done early in the project, goes a long way in
building resilient automated tests. Aer all, no one likes to spend a huge amount of time debugging
test failures that are not functional in nature.
Test environment provisioning and conguration should be automated at all costs. Manual setup
increases the cycle time and adds unnecessary overhead for testers and infrastructure teams. A wide
variety of tools such as Terraform and Chef are available on the market for this purpose. Although
responsibility for the provisioning of various environments lies with the infrastructure team, it does
not hurt for the test engineers to gain a basic understanding of these tools. An ideal environment
provisioning approach would address setting up the infrastructure (where the application will run),
congurations (behavior of the application in the underlying infrastructure), and dependencies
(external modules needed for the functioning of the application) in an automated manner.
Apart from a few high-level checks, any additional testing in production is usually frowned upon. New
code changes are usually soaked in a pre-production environment and later released to production when
the testing is complete (manual and automated). But in recent times, feature ags are being routinely
used to turn o/on new code changes without breaking existing functionality in production. Testing
in production can be localized to a minor subset of features by using feature ags eectively. Even if
there are features broken by the introduction of new code changes, the impact would be minimal. Test
automation strategy helps maintain sanity by providing adequate test coverage for critical features
before they are deployed to production. Irrespective of the state of feature ags, primary business ows
should be functional, and it is a prime responsibility of test automation to keep it that way.
26 Test Automation Strategy
Note
Automated tests are only as good as the environment they run against. An unstable test
environment adversely impacts the accuracy, eciency, and eectiveness of the test scripts.
Let us next see how a test automation strategy enables quality in an Agile landscape.
A primary goal in the Agile journey is to enhance the soware quality at every iteration. Test automation
strategy should have automated builds and deployment as a pre-requisite. Only when build automation
is coupled with automated tests is continuous improvement enabled. is is how teams can maximize
their velocity in the Agile landscape while maintaining high quality.
Another key aspect to zero in on is the ability to get feedback early and oen. It helps tremendously
to instill a test-rst mentality in every member of the team. When an engineer thinks through the
feature and which kinds of tests should pass before writing any code, the output is bound to be of
high quality. is also keeps the team from accruing any technical debt in terms of test automation.
Knowing your test automation strategy 27
Attentive and incremental investments in test automation should be the foundation of the strategy, and
it goes a long way in tackling the frequent code changes in Agile development. Sprint retrospections
can be used to pause and reect on areas where Agile principles are not being eectively applied to
test automation strategy.
Agile testing quadrants provide a logical way to organize dierent kinds of tests based on whether
they are business-facing or technology-facing. Let us quickly look at which types of tests are written
in each of the quadrants, as follows:
• Quadrant 1: Highly technical tests written by the programmers, usually in the same programming
language as the soware application.
• Quadrant 2: Tests that verify business functions and use cases. ese tests can be automated
or manual and are used to conrm product behavior with the specications.
• Quadrant 3: Manual tests that verify the user experience (UX) and functionality of the product
through the eyes of a real user.
• Quadrant 4: Tool-intensive tests that verify non-functional aspects of the application such as
performance and security.
Test automation strategy should also address the diverse needs for tools and processes in each of the
Agile testing quadrants, outlined in the following diagram:
Test automation strategy in an Agile project should promote team collaboration, thus acting as a
strengthening force to achieve superior product quality. Next, let us look at some reporting guidelines
to be incorporated into the test automation strategy.
Figure 2.2 provides a view of all the major constituents of a test automation strategy. A good test
automation strategy would be a combination of these items based on the individual soware application.
Next, let us look at some chief items to consider when devising a good automation strategy.
A test automation tool is only a small part of the test automation strategy. High-priced tools do not
guarantee success if other standards of the test automation framework are missing or below par.
Next, let us consider the subject of a test automation framework and pay attention to the standards
surrounding it.
• Modular test automation framework: In this framework, the application logic and the utilities
that help test the logic are broken down into modules of code. ese modules can be built
on incrementally to accommodate further code changes. An example would be an E2E test
framework where the major application modules have a corresponding test module. Changes
to the validation logic happen only within the revised modules limiting rework and increasing
test eciency.
• Library-based test automation framework: In a library-based framework, the application logic
is written in separate methods, and these methods are grouped into libraries. It is an extremely
reusable and portable test automation framework since libraries can be added as dependencies
externally. Most test automation frameworks are library-based, and this relieves the engineers
from writing redundant code.
• Keyword-driven test automation framework: e application logic being tested is extracted
into a collection of keywords and stored in the framework. ese keywords form the foundation
of test scripts and are used to create and invoke tests for every execution. An example of
this would be the Unied Functional Testing (UFT) tool, formerly known as Quick Test
Professional (QTP). It has inherent support for keyword extraction and organizing libraries
for each of those keywords.
• Data-driven test automation framework: As the name suggests, data drives the tests in this
framework. Reusable components of code are executed over a collection of test data, covering
major parts of the application. A simple example of a data-driven framework would be reading
a collection of data from a database or a comma-separated values (CSV) le and verifying
the application logic on every iteration of the data. ere is usually a need to integrate with a
plugin or driver soware to read the data from the source.
Devising a good test automation strategy 31
Oen, a real-world test automation framework is a combination of two or more of the types shown
in Figure 2.3. e test script acts as a primary driver to invoke helper methods to perform a variety
of tasks. e test script also leverages the environment variables and is responsible for managing the
test results.
Now that we know what a test automation framework is, let us next look at some key components of
every test automation framework.
Both the custom and third-party libraries together form the building blocks of a strong test automation
framework. Whichever form they may be in an automation framework, they hold the essential
application logic and utilities that assist in validating the logic.
Next, let us look at how important it is to have a good platform for running tests.
A test automation framework primarily aims to maintain consistency across test scripts. When test
scripts are created by a team in the organization, they should be available for reuse for any team in the
future. e test automation framework should promote this kind of mobility, which in turn enables
consistency in the way test scripts are created. Test automation should create foundational utilities
for various common actions performed on the soware application, such as downloading a Portable
Document Format (PDF) le, sending an email, and so on.
e test automation framework should also assist engineers in writing tests for components that are
otherwise hard to validate. For example, there could be wrapper code written as part of the test automation
framework that could be used to call a legacy system as part of an integration test. Another use case
would be to support the mocking of external vendor calls within the framework as part of E2E tests.
Test automation should also support tackling bug detection and analysis with minimum human
intervention. It is vital to put in place concise logging mechanisms within the framework for swi
debugging of failures. Integrations with tools such as JIRA and Bamboo can be explored to maintain
uniform reporting of bugs and issues in an automated manner.
It is the responsibility of the test engineers and the soware development engineers in test (SDETs)
to work with the infrastructure team to ensure tests are created and run in the most ecient way
within the limitations of a test environment. Test automation will be cost-prohibitive if none of the
sub-systems is stable or testable. Test engineers always need to be on the lookout for environment-
related errors to establish an uninterrupted automated testing process.
Building a solid test automation framework is only the beginning of the quality journey. ere is
constant eort involved in maintaining and keeping the framework updated. Let us look at some key
factors in maintaining the framework.
One of the chief goals of a test automation framework is to ensure continuous synchronization between
the dierent tools and libraries used. It helps to enable automatic updates of various third-party
libraries used in the framework as part of the continuous integration (CI) pipeline to circumvent
manual intervention. Any test tool utilized within the framework should constantly be evaluated for
enhancements and security vulnerabilities. Documenting the best practices around handling the
framework helps newly onboarded engineers to hit the ground running in less time. Having dedicated
SDETs acting as a liaison with tool vendors and users adds stability to the overall test automation process.
Devising a good test automation strategy 33
It goes without saying the importance of keeping test scripts updated with code changes. SDETs
need to stay on top of code changes that render the automation framework inoperable, while the test
engineers should continuously look out for code changes that break the test scripts. Test engineers
should eciently balance their time between adding new tests versus updating existing ones to keep
the CI pipeline functional. Test automation framework maintenance takes time and sometimes
involves signicant code changes. It is important to plan and allocate time upfront for the maintenance
and enhancements of the framework. It is crucial to spend more time designing and optimizing the
framework as this helps in saving time in maintenance down the road.
Next, let us review key factors in handling test data as part of the test automation framework.
Acquiring test data and cleaning it up for sustainable usage in testing is a key task of an automation
framework. A lot of cross-team collaboration must happen to build a repository of high-quality test
data. Test engineers and SDETs oen work with product teams and data analysts to map test scenarios
with the datasets that might already be available. Additional queries will have to be run against
production databases to cover any gaps identied in this process. Test data thus acquired is static and
should be masked to eliminate any personally identiable information (PII) for usage within the
test automation framework, calling out some of this static data.
A plethora of data-generating libraries are also available for integration with the framework. ese
libraries can be equipped to handle simple spreadsheets to generate unstructured data based on
business logic. Oen, there is a need to write custom code to extract, generate, and store test data
due to the complexity of soware applications. Every automation framework is unique and requires
a combination of static and dynamic data generation techniques. It is a good practice to isolate these
test data generation libraries for portability and reusability across the organization.
Always try to focus on the quality of test data over quantity. e framework should also include
utilities for cleaning up the test data aer every test execution to preserve the state of the application.
ere should be common methods set up to handle test data creation and deletion as part of every
test automation framework.
Test data management is a separate domain by itself, and we are just scratching the surface. Let us
quickly look at some additional factors in handling and maintaining sanity around test data, as follows:
• Maintaining data integrity throughout its usage in test scripts is essential to the reliability of
tests. e automation framework should oer options to clean and reuse test data when and
where necessary.
• Guarding the test data for use outside of automation should be avoided at all costs. Maintaining
clear communication on which data is being used for test automation keeps the automated
tests cleaner.
34 Test Automation Strategy
• Performing data backups of baseline data used for automated testing and using them in the
future will help immensely in recreating data across test environments.
• Using data stubs/mocks when dealing with external vendor data or for internal application
programming interfaces (APIs) that may not have high availability (HA). Typical responses
can be saved and replayed by the stubs/mocks wherever necessary in the framework.
• Employing data generators to introduce randomness and to avoid using real-time data within
the tests. ere are numerous generators available for commonly used data such as addresses
and PII.
• Considering all the integration points within the application when implementing utilities that
create underlying test data.
• Including user interface (UI) limitations when designing test data for E2E tests. is is especially
useful when using API calls to set up data for UI tests as there might be incompatibilities
between how data is handled by dierent layers of the application stack.
e aspects of the test automation framework that we reviewed so far are mostly agnostic to the hosting
environment—that is, on-premise or cloud—but there are certain distinct benets to embracing the
cloud in the overall test automation strategy. Let us look at them in the next section.
With a good notion of various aspects of the test automation framework, let us next dive into
understanding the test pyramid.
Unit/component tests
ey are tests dened at the lowest level of the system. ey are written by the engineer developing
the feature, and the involvement of test engineers is minimal (and sometimes zero) in these tests.
ey form a healthy collection of tests, providing excellent coverage for all the code components.
Frameworks used to put these tests in place include xUnit, Rspec, and more. ey are completely
automated, and these tests should ideally run for every commit to the code repository. External and
database calls are stubbed in this layer, which contributes to the increased speed of these tests. Since
they are the quickest and the least expensive to write, they come with the biggest ROI among all other
types of tests. ey also enable swi feedback due to their high frequency of execution.
36 Test Automation Strategy
Certain non-functional tests can also be included as component tests in this layer, with additional
setup and partnership with the infrastructure team. Test automation strategy should also comprise
techniques to quarantine aky unit tests. is is usually the bulkiest layer of the pyramid, and any
application that can be tested should be included as part of unit/component tests.
e main drawback of unit tests is that they fall short in identifying bugs and errors resulting from
the communication of multiple code modules.
Next, let us look at how integration/API tests help with validating communication that extends beyond
a module of code.
Integration/API tests
e second layer in the pyramid is where the majority of the application logic is validated. Tests in
this layer can be tied directly back to a feature or a combination of features. Ideally, these tests should
be executed before merging the code into the master branch. If that is not possible, these should be
run as soon as the code change is deployed to a testing environment. Since these tests make frequent
database or other mocked external calls, their execution time is generally high.
is layer is also apt for verifying API contracts and how APIs communicate with each other. Aer
analyzing production data and setting up inputs for these APIs, the output can be compared to the
expected behavior. Care must be taken to exclude any UI-based tests in this layer. While there is a
comprise on the speed of execution, these tests tend to oer higher coverage as they span more lines
of code in a single test.
Integration/API tests sometimes can be time-consuming and resource-intensive when the link between
every API and module must be veried. is is where system tests come in handy. Let us examine
and understand the top layer of the pyramid next, comprising system tests.
E2E/System/UI tests
ese are tests that exercise the soware application through its UI or a series of API calls to validate
a business ow. ese require a test environment with all the dependencies, associated databases, and
mocked vendor calls. ese tests are not run as frequently as unit and API tests due to their extensive
runtimes. e main goal of these tests is to give product and engineering teams the condence to deploy
the code to production. Since most of the bugs should already be found by the lower-level tests, the
frequency of execution of these tests can be adjusted to synchronize with the production release cycles.
ese tests also act as acceptance tests for business teams or even the client in some projects. An
example would be Selenium tests, which simulate how a real user performs actions on the application.
ey verify all aspects of the application like a real user would do. Controls must be in place to avoid
using real user data from production.
Next, let us examine how to structure the dierent types of tests for optimal results.
Familiarizing ourselves with common design patterns 37
• Automate as many test cases as you need, but no more, and automate them at the lowest level
that you can.
• Always try to curb the scope of each test case to one test condition or one business rule. Although
this may be dicult in some cases, it goes a long way in keeping your test suite concise and
makes debugging much easier.
• It is essential to have clarity on the purpose of each test and avoid dependencies between tests
because they quickly increase complexity and maintenance expenses.
• Plan test execution intervals based on test types to maximize bug detection and minimize
execution times of the CI pipeline.
• Identify and implement mechanisms to catch and quarantine aky tests as part of every test
execution.
We saw in detail how the test pyramid assists in strategizing test automation. Let us next dive into
some common design patterns used in test automation.
• Saves time and eort in addressing common test automation design challenges
• Reduces code maintenance costs
Some common design patterns employed in test automation are noted here:
POM
Object repositories, in general, help keep the objects used in a test script in a central location rather
than having them spread across the tests. POM is one of the most used design patterns in test
automation; it aids in minimizing duplicate code and makes code maintenance easier. A page object
is a class dened to hold elements and methods related to a page on the UI, and this object can be
instantiated within the test script. e test can then use these elements and methods to interact with
the elements on the page.
Let us imagine a simple web page that serves as an application for various kinds of loans (such as
personal loans, quick money loans, and so on). ere may be multiple business ows associated with
this single web page, and these can be set up as dierent test cases with distinct outcomes. e test
script would be accessing the same UI elements for these ows except when selecting the type of loan
to apply for. POM would be a useful design pattern here as the UI elements can be declared within the
page object class and utilized in each of the dierent tests running the business ows. Whenever there
is an addition or change to the elements on the UI, the page object class is the only place to be updated.
e following code snippet illustrates the creation of a simple page object class and how the test_
search_title test uses common elements on the UI from the Home_Page_Object page object
class to perform its actions:
class WebDriverManagerFactory:
def getWebdriverForBrowser(browserName):
if browserName==firefox:
return webdriver.Firefox()
elif browserName==chrome:
return webdriver.Chrome()
elif browserName==edge:
Familiarizing ourselves with common design patterns 39
return webdriver.Edge()
else:
return No match
class Home_Page_Object:
def __init__(self, driver):
self.driver = driver
def load_home_page(self):
self.driver.get("https://www.packtpub.com/")
return self
def load_page(self,url):
self.driver.get(url)
return self
def search_for_title(self, search_text):
self.driver.find_element(By.ID,search).send_keys(search_text)
search_button=self.driver.find_element(By.XPATH, //button[@
class="action search"])
search_button.click()
def tear_down(self):
self.driver.close()
e POM paradigm usually has a base class that contains methods for identifying various elements
on the page and the actions to be performed on them. e Home_Page_Object class here in this
example has methods to set up the driver, load the home page, search for titles, and close the driver:
class Test_Script:
def test_1(self):
driver = WebDriverManagerFactory
.getWebdriverForBrowser("chrome")
if driver == No match:
raise Exception("No matching browsers found")
pageObject = Home_Page_Object(driver)
pageObject.load_home_page()
pageObject.search_for_title(quality)
40 Test Automation Strategy
pageObject.tear_down()
def main():
test_executor = Test_Script()
test_executor.test_1()
if __name__ == "__main__":
main()
e test_search_title method sets up the Chrome driver and the page object to search for
the quality string.
We will look in further detail about setting up and using POM in Chapter 5, Test Automation for Web.
Now, let us investigate how the factory design pattern is helpful in test automation.
e factory pattern is one of the most used design patterns in test automation and aids in creating and
managing test data. e creation and maintenance of test data within a test automation framework
could easily get messy, and this approach provides a clean way to create the required objects in the
test script, thereby decoupling the specics of the factory classes from the automation framework.
Separating the data logic from the test also helps test engineers keep the code clean, maintainable, and
easier to read. is is oen achieved in test automation by using pre-built libraries and instantiating
objects from classes exposed by the libraries. Test engineers can use the resulting object in their scripts
without the need to modify any of the underlying implementations.
A classic example of a factory design pattern in test automation would be how Selenium WebDriver
gets initialized and passed around in a test. Selenium WebDriver is a framework that enables the
execution of cross-browser tests.
e following diagram breaks down how a piece of test script can exercise Selenium WebDriver to
make cross-browser calls:
Familiarizing ourselves with common design patterns 41
Figure 2.5 shows how the test code utilizes a factory method to initialize and use the web drivers.
Please refer to the code snippet in the previous section for a simple implementation of the factory
pattern. Here, the WebDriverManagerFactory class returns an instance of the web driver for
the requested browser. e Test_Search_Choose_Title class can use the factory method to
open a Chrome browser and perform additional validations. Any changes to how drivers are being
created are encapsulated from the test script. If Selenium WebDriver supports additional browsers in
the future, the factory method will be updated to return the corresponding driver.
is is an architectural design pattern where the test code is designed to handle each layer of the
application stack separately. e libraries or modules that serve the test script are intentionally broken
down into UI, business logic/API, and data handling. is kind of design is immensely helpful when
writing E2E tests where there is a constant need to interface with the full stack. For example, the steps
involved may be to start with seeding the database with the pre-requisite data, make a series of API
calls to execute business ows, and nally validate the UI for correctness. It is critical here to keep the
layers separate as this reduces the code maintenance nightmare. Since each of the layers is abstracted,
this design pattern promotes reusability. All the business logic is exercised in the API layer, and the
UI layer is kept light to enhance the stability of the framework.
Design patterns play a key role in improving the overall test automation process and they should be
applied aer thoroughly understanding the underlying problem. We need to be wary of the fact that
if applied incorrectly, these design patterns could lead to unnecessary complications.
42 Test Automation Strategy
Summary
In this chapter, we dealt primarily with how to come up with a sound test automation strategy. First,
we saw some chief objectives that need to be dened to get started with the test automation eort, then
we reviewed key aspects in devising a good test automation strategy. We also looked at how the test
pyramid helps in formulating a test strategy by breaking down the types of tests. Finally, we surveyed
how design patterns can be useful in test automation and learned about some common design patterns.
Now that we have gained solid ground on test automation strategy, in the next chapter, let us look
at some useful command-line tools and analyze in detail certain commonly used test automation
frameworks and the considerations around them.
Questions
Take a look at the following questions to test your knowledge of the concepts learned in this chapter:
Technical requirements
In this chapter, we will be looking at working examples of the CLI and Git. We will be using the
Terminal soware on macOS for our examples in both sections. Windows users can use the in-built
PowerShell to execute these commands.
under test. is section is a quick refresher for readers who are already experienced in the soware
engineering space, and can help to build a good foundation for beginners.
Let us start by looking at the CLI.
The CLI
e CLI is a means to interact with the shell of the system under test. A lot of the tasks performed
through the graphical user interface can be done through the CLI too. But, the real might of the CLI
lies in its ability to programmatically support the simulation of these tasks. Let’s try and get familiar
with a few basic CLI commands. e CLI commands covered in this section can be run on Terminal
soware on macOS, or PowerShell on Windows:
• e ls command lists all the les and directories in the current folder:
➜ls
e output to the preceding command should be as follows:
test.py test.txt testing_1 testing_2 testing_3
testing_4
➜
• e cd command stands for change directory and is used to switch to another directory. e
cd .. command navigates to the parent directory.
e syntax is as follows:
cd [path_to_directory]
e command and output should be as follows:
➜cd testing_1➜ testing_1 cd ..
• e touch command creates a new le in the current directory without a preview.
e syntax is as follows:
touch [file_name]
e command and output should be as follows:
➜ touch testing.txt
➜ls
test.py test.txt testing.txt testing_1 testing_2
testing_3 testing_4 testing_5
Note
Windows PowerShell users can use ni as touch is not supported.
• e cat command allows the user to view le contents on the CLI.
e syntax is as follows:
cat [file_name]
e command and output should be as follows:
➜ cat vim_file
This is a new file
➜ cli_demo
So far, we have looked at how to create and modify les. Next, let us look at the commands for deleting
les and folders:
• e rm command can be used to delete folders and les. Let us look at some specic examples
of how to go about this deletion.
To remove a directory and all the contents under that directory, use the rm command with
the –r option.
e syntax is as follows:
rm r [directory_name]
e command and output should be as follows:
➜ ls
test.py test.txt testing.txt testing_1 testing_2
testing_3 testing_4 testing_5 vim_file
➜ rm -r testing_1
46 Common Tools and Frameworks
➜ls
test.py test.txt testing.txt testing_2 testing_3
testing_4 testing_5 vim_file
➜
• To delete the le(s), the same rm command can be used followed by the lename.
e syntax is as follows:
rm [file_name]
e command and output should be as follows:
➜ cli_demo ls
test.py test.txt testing.txt testing_2 testing_3
testing_4 testing_5 vim_file
➜ cli_demo rm test.txt
➜ cli_demo ls
test.py testing.txt testing_2 testing_3
testing_4 testing_5 vim_file
➜ cli_demo
Next, let us quickly look at Vim, which is a commonly used le-handling tool for the CLI.
Vim is an in-built editor that allows you to modify the contents of a le. Vim aims to increase eciency
when editing code via the CLI and is supported across all major platforms, such as macOS, Windows,
and Linux. Vim also supports creating custom keyboard shortcuts based on your typing needs. Let’s
look at a basic example of editing and saving a le. is editor supports a wide range of commands
and can be referenced at http://vimdoc.sourceforge.net/. To edit and save a le, you
need to do the following:
1. To execute the editor, the user has to type vi, followed by a space and the lename:
workspace vi test.txt
2. en, type i to switch to INSERT mode and type in the contents of the le.
3. Press the Esc key to quit INSERT mode.
4. Next, type :wq to save and exit. is command is a combination of :w to write the contents
of the le to the disk and q to quit the le.
5. en, press i to enter INSERT mode and type the required contents in the le.
The basic tools for every automation engineer 47
e CLI commands we have looked at so far should serve as a good starting point for new users. Now,
let us familiarize ourselves with ags in the CLI.
Flags are add-ons to enhance the usage of a command in the CLI. For example, the –l ag can be
applied to the ls command to alter the displayed list of les and folders in a long format.
e syntax is as follows:
ls l
➜ls -l
total 8
-rw-r--r-- 1 packt staff 0 Jun 25 09:33 test.py
-rw-r--r-- 1 packt staff 0 Aug 14 18:14 testing.txt
drwxr-xr-x 3 packt staff 96 Jun 26 10:20 testing_2
drwxr-xr-x 2 packt staff 64 Jun 25 09:32 testing_3
drwxr-xr-x 2 packt staff 64 Jun 25 23:16 testing_4
drwxr-xr-x 2 packt staff 64 Aug 14 18:13 testing_5
-rw-r--r-- 1 packt staff 19 Aug 14 18:26 vim_file
➜
ere are thousands of ags that can be attached to various CLI commands, and it is impossible to
know all of them. is is where the man command comes in handy. man can be used with any CLI
command, and it gives all the options and an associated description for each command. ere are
usually multiple pages of help content and you are encouraged to browse through them.
For example, to learn all the information associated with the ls commands, you just have to run the
following command:
man ls
ere are a few tips/tricks to keep in mind regarding CLI usage, such as the following:
• e cd – and cd ~ commands can be used to navigate to the last working directory and
home directory, respectively
• Multiple CLI commands can be run in a single line using the ; separator
e ultimate utility of the CLI lies in writing automated scripts that perform repeatable tasks. Shell
scripting can be used to achieve this and can save you a great deal of time. Users are encouraged to
refer to the full documentation at https://www.gnu.org/software/bash/manual/bash.
html to learn more about commands and their syntax. To understand the power of the CLI, let us
look at an example of a shell script in this section. is script creates a folder, named test_folder,
and then creates a text le, named test_file, within it. e script then uses the curl command
to download a web resource that is passed as an argument and stores its output in test_file.txt.
Now, $1 refers to the rst argument used when invoking this le for execution. -o is used to override
the contents of the le. en, it reads the le using the cat command and stores it in a variable named
file_content. Finally, this le is removed using the rm command:
#!/bin/bash
mkdir test_folder
cd test_folder
touch test_file.txt
curl $1 -o test_file.txt
file_content=`cat test_file.txt`
echo $file_content
rm test_file.txt
is script can be executed using the bash sample_bash_script.sh https://www.
packt.com/ command, where sample_bash_script.sh is the name of the le. Please note
that the web resource here can be downloaded at https://www.packt.com/ and that it is being
passed as the rst argument to the script.
We have just gotten a bird’s eye view of the CLI, and I strongly encourage you to dive deeper into CLI
commands to increase your prociency. Some major advantages of using the CLI include the following:
• Speed and security: CLI commands are faster and more secure to use than the corresponding
actions being done through the graphical user interface.
• Scripting on the CLI: e CLI lets users write scripts to perform repetitive actions by combining
them into a single script le. is is much more stable and ecient than a script run on a
graphical user interface.
The basic tools for every automation engineer 49
• Resource ecient: CLI commands use much fewer system resources and therefore provide
better stability.
Now that we have familiarized ourselves with the CLI, let us look at another tool that is an absolute
necessity for the maintenance of a soware project of any size.
Git
Git is a modern distributed version control system that allows tracking changes to the source code and
is a versatile tool to enable collaboration in the engineering team. Git primarily helps in synchronizing
contributions to source code by various members of the team, by keeping track of the progress over time.
Every soware application is broken down into code repositories and production code is stored on
a branch called master on the repository. When an engineer is ready to begin working on a feature,
they can clone the repository locally and create a new branch to make their changes. Aer the code
changes are complete, the engineer creates a pull request that is then peer-reviewed and approved.
is is when they are merged into the master branch. Subsequently, the changes are deployed to the
staging and production environments. ere are various hosting services, such as GitHub, that provide
a user interface to maintain, track, and coordinate contributions to the code repositories. Now, let us
look at some of the common Git commands that test engineers might have to use frequently:
• git --version shows the version of Git soware installed on the machine:
• git push pushes all of the committed local changes to the remote GitHub repository:
• git pull pulls all the latest code from the remote branch and merges them with the local
branch:
The basic tools for every automation engineer 51
• git branch [branch_name] creates a new branch in the local Git repository:
• git branch lists all the local branches created so far. * indicates the branch that is currently
checked out:
• git branch –a lists all the local and remote branches created so far:
• git status displays the modied les and folders in the current project repository:
• git diff shows the dierence between les in the staging area and the working tree:
• git add . adds all the modied les to the Git staging area:
• git commit –m "commit description" saves the changes to the local repository
with the provided description:
• git remote -v gives the name, as well as the URL, of the remote repository:
is overview provides you with a healthy introduction to Git and its most commonly used commands.
You can explore additional commands and their usage here at https://git-scm.com/docs/
git. Next, let us dive into some of the most commonly used test automation frameworks.
Selenium
Selenium is an open source tool that provides an interface to automate user actions on web browsers.
Imagine a manual tester that must test the login page of an application. ere are a variety of scenarios
that can be run such as validating various kinds of inputs, empty elds, and incorrect entries. is
must be done across multiple browsers such as Chrome, Firefox, and Safari. Also, whenever there is
a code change that impacts the login page, these tests must be repeated. Even though this is a simple
scenario, in the real world, the eorts involved to test and keep retesting the changes can compound
swily. When we apply this logic to testing the business ows of a complex enterprise application,
modern soware engineering teams simply do not have the capacity to scale the manual testing. is
is where Selenium can turbocharge browser testing, helping soware engineers and product teams
tremendously.
58 Common Tools and Frameworks
Components of Selenium
At a high level, Selenium has three components that help create and orchestrate the tests. Let us look
at each one of the following components:
High-level architecture
We looked at how WebDriver orchestrates the call to execute tests on the browser in Chapter 2,
specically the e Factories pattern section. Here, we look at the illustration again in Figure 3.18.
e test script initializes WebDriver, which sends the commands to the local browser instance. e
driver executes the commands on the browser instance.
In cases where parallel test runs are required, the hub orchestrates the requests from a client and
spreads them across multiple devices containing remote web drivers, as shown in Figure 3.19. A remote
WebDriver instance has two internal components: a client running the test script, and a server to run
the test on a remote device.
Selenium is very exible in its setup, and hence it’s very popular among test and soware engineers.
Most browsers today have built-in support for Selenium testing, making it a very handy tool. Like
any other open source tool, Selenium depends on community contributions for support through
third-party libraries. Since it was open-sourced more than a decade ago, there have been continuous
improvements done by users. e Selenium project can be found at https://github.com/
SeleniumHQ.
Now, for the testing of our hypothetical banking application, Selenium can primarily be used to verify
frontend aspects. We should be creating page object models for each of the pages and capturing UI
elements using appropriate selectors. en, we need to create a script to load the URL of the application
and verify the ow along with the interaction of these elements. Scripts should also be set up to create
the drivers and execute them on various browsers.
Even though Selenium is multi-faceted in browser automation, it lacks depth in supporting mobile-
native applications. In the next section, let us look at Appium, which is a specialized tool for automating
mobile-native applications.
60 Common Tools and Frameworks
Appium
Appium is an open source tool used for automating tests on platforms such as Android and iOS.
It also supports mobile browser automation with extensive community support. Appium provides
libraries backing a variety of programming languages, such as Java, Python, PHP, C#, JavaScript, and
Ruby. Before diving into Appium’s architecture, let us look at the distinct kinds of mobile applications:
• Native apps: ese are apps written on Android and iOS platforms that can be interacted with
only aer complete installation on the device
• Hybrid apps: ese are apps that can be installed on the device, as well as accessed through
a browser URL
• Web apps: ese are apps that can be used only via a mobile browser
Appium oers a single API that can be used to write tests across all these platforms and greatly enables
the reuse of test code. Now, let us look at what Appium comprises.
Components of Appium
• Appium Client: Appium Client is the test script written to validate the logic of the mobile/
web application. It also includes the detailed conguration used to access the various mobile
platforms. Appium Client comes with libraries, with support for a wide variety of programming
languages.
• Appium Server: Appium Server is the component that interacts with the client and transfers
the commands to the end device. It is written in Node.js and parses the request from the client
into a JSON format and relays them to the devices or an emulator.
• Device/emulator: ese are mobile devices or emulators on which the test code sent by the
Appium client is executed by the server.
High-level architecture
As seen in the previous section, Appium is built on a client-server architecture. As shown in Figure
3.20, it comprises an HTTP server written on Node.js. Appium Client communicates with the server
using RESTful APIs through MOBILE JSON WIRE PROTOCOL.
Common test automation frameworks 61
It is vital to know that Appium uses Selenium WebDriver commands to interact with the mobile
interface. Appium Client libraries convert the test code into REST API requests and establish a session
with the server. ese requests are then forwarded by the server to the devices/emulators. Appium
Client and the server use this session ID as a reference for their communication. Apple and Android
devices have their own APIs to expose the UI elements on their devices. Appium interacts with these
elements by sending JSON commands to these APIs.
For testing our hypothetical banking application, we would rst set up the Appium server and add
platform-specic conguration to support iOS and Android applications. We would also set up
virtual devices with an appropriate version of the OS on emulators. With both the emulators and
the Appium server set up, we can create and execute test scripts to validate the UI elements from the
mobile application. We could also perform a similar conguration for physical mobile devices and
run the tests on them.
is is the high-level architecture of the Appium tool. In Chapter 6, Test Automation for Mobile, we
will look at a test case’s implementation using Appium. In the meantime, you can refer to Appium’s
ocial documentation at https://appium.io/docs/en/about-appium/intro/. Now
let us turn our attention to Cypress, which is another eective web automation tool.
62 Common Tools and Frameworks
Cypress
Cypress is an open source tool written in JavaScript and is primarily used for web automation testing.
e main dierence between Cypress and Selenium is that Cypress works directly on the browser,
whereas Selenium interacts via drivers. Cypress also has the capability to run tests across multiple
browsers. It can detect the browsers installed on a particular machine and display them as an option
for test execution. Cypress comes in-built with the ability to access both frontend and backend parts of
the application. is makes it a great E2E testing tool and is deemed a next-generation test automation
tool for the modern web. Cypress is especially easy to set up and quickly functional in JavaScript-based
environments. Now, let us look at the chief components of the Cypress tool.
Components of Cypress
Since Cypress is a Node.js application, it has a remarkably simple yet powerful architecture. Cypress
sits directly on the browser itself and executes the commands taking full control of the browser
automation. e components involved are few, but they are amazingly eective:
• Cypress Node.js server: is is the server on which Cypress runs and communicates with the
test runner. is server constantly synchronizes the tasks between the test runner and itself,
thereby enabling real-time responses to the application events.
• Cypress test runner: Cypress comes with an interactive test runner that shows the execution
of commands as they run against the application.
Now, let us dig deeper into the architecture and inner workings of the Cypress tool.
High-level architecture
As mentioned in the previous sections, Cypress comprises a Node.js server that sits directly on the
browser to execute the test commands. e Node.js server and Cypress constantly interact to keep total
control of the frontend and backend aspects of the application under test. Cypress not only accesses
the DOM and other browser objects but also monitors the networking layer. is helps it dictate
actions both within and outside the browser. Figure 3.21 provides a diagrammatic representation of
this architecture:
Common test automation frameworks 63
Since the browser directly runs the Cypress tests, the test’s behavior can be modied dynamically by
accessing the network trac. For further reading on Cypress, you can refer to the documentation at
https://docs.cypress.io. We will implement a test script using the Cypress tool in Chapter
5, Test Automation for the Web.
Cypress can be eectively used to set up E2E test scenarios for our hypothetical banking application.
We could follow a similar approach as that of Selenium for setting up page objects to verify interaction
with the frontend aspects of the application. Additionally, we could intercept the backend API calls
and add validations to them. In this case, we would have test scripts covering multiple E2E ows,
verifying both UI elements and the API responses involved in that ow.
Next, let us look at a performance testing tool.
JMeter
JMeter is an open source performance testing tool that simulates user requests to a server and then
computes and stores the response statistics from the server. It comes with an intuitive user interface
that assists in designing various parameters of the tests. It is a versatile tool that can be congured to
run in a multithreaded fashion on Linux and Windows machines. It also supports a wide variety of
protocols, such as REST, HTTPS, SOAP, Mail/SMTP, and JDBC. Let us look at the dierent components
of the JMeter tool.
64 Common Tools and Frameworks
Components of JMeter
• JMeter master: is is a core component that congures the workers and integrates all the
test results
• JMeter slave nodes: Distributes virtual machines used to run the tests
• User interface: is is a lightweight interface built using the Java swing component that can
be used for test maintenance and conguration
Now that we are aware of the components within JMeter, let us look at its high-level architecture.
High-level architecture
JMeter uses the master-slave architecture where the tests can be scaled dynamically by increasing the
number of slave nodes, thereby simulating real-time web trac. e master node acts as an orchestrator
where the tests are triggered and helps to spread the load across multiple nodes. Tests can be invoked
via the CLI or the UI. Figure 3.22 illustrates the inner workings of the JMeter architecture:
By sampling many threads simultaneously, JMeter eectively helps determine the performance of web
applications. e ocial documentation for JMeter can be found at https://jmeter.apache.
org/usermanual/index.html. We will look at a detailed implementation of a performance
test in Chapter 8, Test Automation for Performance.
Common test automation frameworks 65
In the case of our banking application, we would initially look at setting up performance tests for each of
the APIs. Every API should conform to an SLA in terms of the maximum number of concurrent users
and response times. JMeter can be used to set up and verify that. en, we move on to performance
test the response times on the UI screens. We normally start with a minimal number of concurrent
users and gradually throttle that number to observe the response times of the web pages. We could
also stress test both the APIs and the UI pages by increasing the concurrent users to a point where it
breaks the application.
Next, let us look at an accessibility testing tool, AXE.
AXE
Axe is a lightweight browser-based accessibility testing tool that is available as an extension. It checks
a web page against pre-dened accessibility rules and generates a report of compliances/violations.
It also provides options to check parts of a page and generate insights based on the generated report.
ere are additional libraries available to check compliance against audits and continuously monitor
the accessibility status of the web page. You can further explore the capabilities of this tool by referring
to https://www.deque.com/axe/core-documentation/api-documentation/.
For testing our hypothetical banking application, we would be adding the AXE tool plugin to our browser
to get real-time feedback on the level of accessibility support. We could also explore implementing
their linters within the application code bases to automatically review every merge.
We have looked at a sample of test automation tools and their high-level architecture so far in this
chapter. Table 3.1 summarizes their primary usage and support:
A common question that lingers in the minds of testing teams is how to pick the right tool for the
task at hand. In the next section, we will look at some standard considerations in picking the right
tool for the various kinds of testing.
Next, let us look at similar tool selection criteria for API testing.
Choosing the right tool/framework 67
Even though extensive API testing provides sizeable test coverage, there are parts of the application
that cannot be tested using APIs. is is where a good web testing tool comes in handy. Let us review
the items to look for in a solid web testing tool.
• Support for specic platforms and technologies used by the application being tested
• Stability when setting up long-running end-to-end tests
• Support for capture and playback tests for getting tests up and running in a brief time
• e ability to monitor and inspect backend parts of the application while running frontend tests
• Support for constant improvements and documentation
us, a good web testing tool must be well rounded in its coverage to address end-to-end aspects of
the application. Next, let us look at the factors that inuence a mobile testing tool selection.
68 Common Tools and Frameworks
Mobile
A major chunk of the factors that we have looked at so far apply to mobile testing tools as well. Here,
in this section, let us list the specic criteria that apply to mobile testing:
In the next section, let us examine the common factors that play a key role in a user settling on a
particular tool.
Common considerations
Every kind of testing demands its own set of standards in a test automation tool. But there are certain
common details that must be analyzed upfront in this process. Let us examine them in this section.
CI/CD integration
Irrespective of the tool or the type of testing being performed, integration with a CI/CD tool is an
absolute must in the current soware engineering landscape. e tool’s ability to integrate with the
current development infrastructure with ease is critical. Sometimes, the introduction of a new tool in
the testing ecosystem demands soware engineers to change the way they deliver soware. e tool
should oer plugins or other installable tools to blend with the CI/CD pipeline, thus paving the way for
engineers to focus on writing the tests, with the tool taking care of the integration automatically. In fact,
a testing tool should be an enabler of strong CI/CD processes if the team does not already have one.
Next, let us review some budget considerations while selecting a test automation tool.
Usually, one of the chief aspects of deciding on a test automation is its cost. Deciding between open
source and building one from scratch is usually the rst step. is depends immensely on the available
time and resources at disposal. ere should also be an upfront analysis done on the diverse options
available in the licensed version to evaluate the t. It is useful to analyze the risks involved in not
adopting a tool and build on the benets the tool will eventually oer. It is also important to assess
how the licensing cost will change over time as the engineering organization evolves. It is vital to note
that the introduction of a test automation tool would increase the costs initially, but eventually should
reduce the quality and deployment costs when rightly integrated and used with the DevOps processes.
Let us next look at how having the resources with the right skills accelerates tool adoption.
Summary 69
Even a well-rounded testing tool that is not utilized to its full potential will not deliver the promised
ROI. Having the skilled resources to use the testing tool makes an enormous dierence in the test
automation eort. It is crucial to get the team’s feedback about the tool selection process to make sure
the tool addresses all the pain points faced by the team. Team members should be comfortable with
the scripting language supported by the tool, and proper training must be provided to address the
knowledge gaps. It also helps to select a language that is already being used by the soware engineers
on the team. is gives the team access to more coding experts. Quality engineers should be involved
in the code review process, which would assist them in learning the intricacies and best practices
of the programming language used. It would be wise to produce a tool onboarding plan and get it
reviewed by all the users.
Summary
In this chapter, we looked at and understood some of the chief tools used for quality engineering on
a daily basis. We started with the CLI and looked at some of the commonly used commands. en,
we explored what Git is and familiarized ourselves with basic Git commands to initialize and make
changes to a code repository. We continued to review common test automation frameworks and
their high-level architecture. We gained a solid understanding of the purpose of each of these tools/
frameworks. In the concluding section, we reviewed the tool selection criteria for various kinds of
testing and some common factors that inuence testing tool selection.
Based on the contents of what we have seen in this chapter, you should be able to comfortably work
on the CLI and should also feel ready to contribute via Git. You also gained a thorough understanding
of the commonly used test automation frameworks and the analysis that goes before adopting one.
In the next chapter, we will dive a little deeper into Git commands. We will also learn how to set up
an IDE and familiarize ourselves with JavaScript.
Questions
1. What is the CLI and why is it important?
2. What is Git and how is it used?
3. What is Selenium and what are its components?
4. What is Appium mainly used for?
5. How is Cypress dierent from Selenium?
6. What is JMeter primarily used for?
7. How is AXE used in accessibility testing?
8. What are some common considerations when choosing a test automation tool?
Part 2:
Practical Affairs
We will begin this part by familiarizing ourselves with the basics of JavaScript and some advanced
topics in Git. Subsequently, you will take up various test automation tools hands-on and learn how
to quickly get up and running with them. You will familiarize yourself with their setup and how to
use them to execute a basic test. By the end of this section, you will have acquired the skills to take
up test automation for various platforms.
is part has the following chapters:
Technical requirements
In this chapter, we will continue looking at working examples of Git through the Command-Line
Interface (CLI). We will be using the Terminal soware on the Mac for our examples. Windows users
can use the built-in PowerShell to execute these commands. We will also be downloading and exploring
VS Code, which is an IDE. Please check this page for the download requirements: https://code.
visualstudio.com/docs/supporting/requirements. We also expect you to know the
basics of HTML to follow along with the next section on JavaScript.
All the code snippets can be found in the GitHub repository: https://github.com/
PacktPublishing/B19046_Test-Automation-Engineering-Handbook in the
src/ch4 folder.
74 Getting Started with the Basics
Committing a change
In the previous chapter, we briey looked at what a Git commit command does. e commit
command helps save all the changes made in the local repository.
Now, let’s look at the importance of writing a descriptive commit message.
More oen than not, every soware engineer views the commit history to understand what changes
went in and why they were made. Anyone viewing a commit message should be able to get adequate
context on why a certain change was made. If the commit messages are incomplete, then the engineers
have to endure the tedious process of going through each code dierence in a commit. For a large and
complex commit, this can be very cumbersome. It is, therefore, tremendously important to get into
the habit of taking the time to write clean and concise commit messages.
ere are a few commonly used ags with this command. Let us look at them in action next.
We will look at three of the frequently used ags with the commit command in this section:
• -m: is ag associates a message with the commit. We learned about the usage of this ag in
the previous chapter. Figure 4.1 illustrates adding multiline comments using the git commit
command with the –m ag:
Getting more familiar with Git 75
• --amend: is ag helps modify the most recent commit in the local repository instead of
creating a new commit. Figure 4.3 demonstrates an example where a new le was added in
an initial commit. en, using the --amend and --no-edit ags, a second le is added
to complete the commit. e --no-edit ag allows you to complete the commit without
editing the commit message:
76 Getting Started with the Basics
• -a: is ag automatically commits all the modied and deleted les. Figure 4.4 demonstrates
a commit where one of the les was modied and another deleted. e –a ag is being used
here to stage and commit both these changes in a single step:
In the next section, let us look at an example of resolving a merge conict when pushing and pulling
changes to/from the remote repository.
In another branch, let us try to merge the changes from Figure 4.4, where the git_amend_2.txt
le was deleted. It is evident that these two changes contradict each other. Figure 4.6 shows the merged
changes being fetched from the main branch:
Figure 4.7 shows the result when the conicting branch is being rebased with the main. Rebasing
is the process of combining a chain of commits and applying it on top of a new base commit. Git
automatically creates the new commit and applies it on the current base. Frequent rebasing from the
main/master branch helps keep a sequential project history. At this point in the process, the conicts
have to be resolved manually. e engineer has to look through the le and accept or reject others’
changes based on the project’s needs.
In this case, let’s resolve the merge conict by accepting the incoming changes from the remote
rather than pushing the delete. is is simpler when done through an IDE, as shown in Figure 4.8.
On navigating to the source control pane in the IDE and by right clicking the le, the user is shown
an option to accept the incoming changes:
Figure 4.9 shows the result of staging the accepted changes, which results in the deleted le being
retained with the modied contents from the main branch:
80 Getting Started with the Basics
Now that the merge conict is resolved, the rebase can be continued using git rebase --continue
to complete the commit and merge process subsequently. It is important to remember to pull from
remote or other branches (if necessary) before beginning any new work on the local code base.
is keeps the branch updated, thereby reducing merge conicts. It is also vital to have continued
communication with the rest of the team when deciding which changes to accept/reject when resolving
merge conicts. Next, let’s look at a few additional Git commands that might help you save a lot of time.
• git bisect: is command helps identify a certain commit that is buggy or caused certain
tests to fail. It uses binary search to narrow down the search to a single commit from hundreds of
commits. e reference for the individual commits can be found using the git log command.
• git cherry-pick: is command helps pick changes from a specic branch and apply
them to the local branch being worked on. It is very helpful in the case when you don’t need
to apply the changes that aren’t relevant to your work or when you would like to test your local
branch with changes from another remote branch.
Using an IDE 81
• git rebase: is command was already used in some of the previous examples, and it helps
simplify the merging process into the master or the main branch. It modies the base of the
local branch to the most recent commit in the main branch.
• git revert: is command provides a safe way to reverse the specied changes. Instead of
deleting changes, it creates a new commit with inverse changes. is helps maintain revision
history for future reference.
• git reset: is is a powerful command that helps move the repository back to an older
commit by removing all the changes aer that commit. It does this by moving the current head
of the branch back to the older commit.
• git reflog: Git keeps track of changes to branches by maintaining reference logs, and this
command helps to view those logs.
is concludes our section on the deeper dive into Git commands. Let us now start understanding
what an IDE is and begin working with one.
Using an IDE
Quality engineering work demands working with various tools, and the right set of tools tends to
make the engineer’s job extremely ecient and productive. An IDE ranks among the top in helping
engineers write and deploy high-quality code with speed and reliability. Before getting into the nitty-
gritty of an IDE, let us try to understand what makes them so powerful. Apart from IDEs, some
programmers prefer using text editors for writing code, and they are nothing more than tools that
help edit text. Programmers regularly spend an enormous amount of time dealing with formatting and
syntax details. ere are text editors that come with syntax highlighting and color-coding that make
their lives easier. ese are usually apt for an experienced programmer. An IDE is a powerful tool that
provides debugging, build management, and IntelliSensing features. It helps the programmer get up
and running with a complex project really quickly. ere is usually some learning curve with using
an IDE and all its capabilities. But once we get familiarized with the features, it can be a great ally for
our daily programming tasks. At the end of the day, it is the individual’s preference on choosing to
work with an editor or an IDE.
Let us consider, in the next section, some crucial factors in selecting an IDE.
Choosing an IDE
Not all IDEs are made equal, and there is a whole array of options available for engineers to choose
from. Let us review some important features to look for in an IDE before settling on one:
• GitHub integration: is is a no-brainer and an absolute must-have since every engineer works
with Git and needs integration with some form of remote code repository such as GitHub. is
mainly provides the comfort of keeping the local code changes synchronized with the rest of
the organization from within the IDE.
82 Getting Started with the Basics
Let us now look at downloading and setting up VS Code, an open source IDE.
1. Review this link for the necessary system requirements to download and set up VS Code:
https://code.visualstudio.com/docs/supporting/requirements.
2. Click on the download link on the installation page to download the executable le:
macOS and Mac: https://code.visualstudio.com/docs/setup/mac
Linux: https://code.visualstudio.com/docs/setup/linux
Windows: https://code.visualstudio.com/docs/setup/windows
3. Extract the downloaded archive le and move the Visual Studio Code application le to the
Applications folder.
Using an IDE 83
4. Double-click the VS Code icon in the Applications folder to open the VS Code IDE.
5. Use the Settings option in the Preferences menu for additional conguration. VS Code has
inherent support for Git provided Git is installed on the machine.
VS Code comes as a lightweight installation and in most cases, engineers would need additional
components installed through the Extensions option in the Preferences menu.
6. Click the Extensions option and search for Prettier, which is a particularly useful tool for
code formatting.
7. Select the Prettier - Code formatter extension and click on the Install button, as shown in
Figure 4.10. is should complete the installation of the extension from the Marketplace.
ere are hundreds of helpful extensions available for installation from the Marketplace. ese
extensions have a wide community of users supporting them, thereby creating a strong ecosystem.
Users are strongly encouraged to browse through the available extensions and install them as necessary.
If you prefer using the CLI for installation, the following shell script can be used for installing VS Code
on macOS. is example uses Homebrew (https://brew.sh/) for CLI installation:
#!/bin/sh
is concludes our section on setting up the IDE. Let us now move on to learning the basics of JavaScript.
Introduction to JavaScript
JavaScript is the most common web programming language, and it is imperative for quality engineers
to familiarize themselves with the basics. With minor exceptions, we will be using JavaScript to
automate various levels of the application stack in the rest of this book. Let us start with the question
of why we should learn JavaScript.
Installing Node.js
One of the easiest ways to execute a JavaScript program is to run it using Node.js. Node.js is a JavaScript
runtime environment created to execute JavaScript code outside of a browser. Use https://nodejs.
org/en/ to download Node.js and navigate through the wizard to complete the installation of the
latest stable version of Node.js. Check the installation using the node --version command.
Introduction to JavaScript 85
Alternatively, you can use Homebrew on macOS or winget on Windows to download it via the CLI.
At the time of writing this book, the latest stable node version is 18.12.1:
Now that we have Node.js installed, let us execute our rst JavaScript program.
We will be using the VS Code IDE to execute the programs for the rest of this book. Let us go through
step by step to execute a simple Hello World program written in JavaScript:
1. e console.log command outputs the message in the parenthesis to the console. Create
a new hello_world.js le and save it with the contents, console.log(hello
world);.
2. Open a new Terminal window by selecting the New terminal option from the Terminal menu.
In the Terminal window, navigate to the folder in which the hello_world.js le exists
and run the node hello_world.js command. is prints out the text hello world
in the console:
➜ B19046_Test-Automation-Engineering-Handbook git:(main)
✗ cd src/ch4
➜ ch4 git:(main) ✗ node hello_world.js
hello world
➜ ch4 git:(main) ✗
We have set up our IDE and are able to execute a simple JavaScript program using Node.js. It is now
time to get started with the basics.
JavaScript basics
Let us start by adding comments in a JavaScript le. Single-line comments can be added using //
and multiline can be added by enclosing within /* */, as shown in Figure 4.11:
86 Getting Started with the Basics
Variables
Variables are references to the storage location. var was the standard declaration command until
ES6. But in ES6, some of the scoping and hoisting issues with var were addressed, and the common
ways to set variables in JavaScript became let and const. e main dierence is that let allows
the variable to be assigned a dierent value later in the program, but const does not. Figure 4.12
demonstrates the code where the variable temperature is being created and reassigned using let.
It also shows the error when attempting to reassign the value of city, which is declared as const:
Note
It is better to use const to declare variables unless there is a need to reassign the value of the
variable.
Data types
Data types fall into two categories: primitives and objects. In primitive data types, the data is assigned
directly to memory. Let us look at the primitive type in this section and devote the next section to objects.
Figure 4.13 shows the code snippet with variable assignment for each of the primitive data types.
string, number, boolean, null, and undefined form the most used primitive data types.
Strings must be dened using double or single quotes. Boolean can contain only true or false
values. Also, note that there isn’t a separate data type for decimal values; it is also a number. Null means
an empty variable with no value. Any variable that is initialized without a value has an undefined
type. Variable types can be tested using typeof followed by the name of the variable:
Note
You might have noticed from Figure 4.13 that null has a typeof object. is is considered a
bug in JavaScript. e explanation for this can be found in this link: https://developer.
mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/
typeof#typeof_null.
In the next section, let us look at strings in a little more detail, as they are a widely used primitive
data type.
ere are a few common string usages and methods that engineers should be aware of.
Figure 4.14 illustrates the concatenation of two strings to produce a meaningful statement. Backticks
can be used to enclose the string with a dollar sign followed by curly brackets with the variable name:
Let us now familiarize ourselves more with strings by working on some properties and methods. A
method is a function that is associated with an object. Methods must be invoked with parenthesis,
while properties do not need them:
Figure 4.15 summarizes how these properties and methods are used with strings:
With this introduction to variables and data types, let us now take on the topic of objects in JavaScript.
In JavaScript, an object is a collection of properties. Objects are rst initialized using a variable name
and assigned to a set of properties. Objects further provide methods to update these properties.
Properties can be of any data type, sometimes even other objects. is enables building complex
objects in JavaScript. Let us start learning about objects with arrays in the next section.
elements in square brackets, []. Subsequently, the elements can be accessed by plugging the index
within []. Let’s look at some commonly used array methods:
Figure 4.17 shows the corresponding outputs. We begin by creating the array and printing it to the
console. en, we add elements to the end and beginning of the array. Subsequently, we work with
the indices of the array, and nally, get the length of the array:
Introduction to JavaScript 91
Unlike a lot of other programming languages, arrays in JavaScript do not throw an Array Out of
Bounds error when trying to access an index greater than or equal to the length of the array. JavaScript
simply returns undefined when trying to access the non-existent index array. Arrays come with
a wide variety of built-in methods, and I would strongly encourage you to browse through them at
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/
Global_Objects/Array. Next, let us look at work with object literals.
structure. Adding an extra property to the object is very simple and looks like a variable assignment.
To further our example, it would be movie[producer]=Danny DeVito:
const prevents reassigning the variable but does not prevent modifying values within an object:
Having learned the basics of JavaScript objects, let us now look at how to destructure one.
Introduction to JavaScript 93
Destructuring an object
Object destructuring is used in JavaScript to extract property values and assign them to other variables.
It has various advantages such as assigning multiple variables in a single statement, accessing properties
from nested objects, and assigning a default value when a property doesn’t exist. We use the same
example as in the previous section but as shown in Figure 4.19, we destructure the movie object by
specifying the name and awards variables within {}. On the right-hand side of the expression, we
specify the movie object. We could also assign them to a variable within the curly brackets to fetch
data from nested objects. Object destructuring was introduced in ECMAScript 6 and prior to this,
extracting and assigning properties in such a way required a lot of boilerplate code.
Arrays of objects
Working with arrays of objects is crucial for quality engineers as a lot of times, the API response
payloads in JSON format have multiple objects embedded within an array and their format is identical
to JavaScript object literals. Let us consider an example where multiple movie objects are embedded
within the movies array. We could use the JSON.stringify method to create a JSON string.
e code snippet in Figure 4.20 demonstrates how to access nested elements in an array of objects
and how to create a JSON string from a JavaScript object:
In the next section, let us learn how to operate with loops and conditional statements.
Loops and conditional statements form a basic pillar of any programming language. ey help reduce
runtime and make the program look cleaner. Let us look at each one of them and understand how
they operate in the next sections, starting with loops.
Introduction to JavaScript 95
Note
One of the common pitfalls while looping through an array is to accidentally exceed the
last index of the array. e condition to check the array should be i<array.length or
i<=array.length-1.
e while loop operates similarly to the for loop, but we set the variable outside of the loop. It is
a common mistake to miss the increment or incorrectly specify the condition. Doing so would result
in an innite loop. Figure 4.22 shows the same logic in the while loop:
96 Getting Started with the Basics
Now, let us loop through the array of objects we created in Figure 4.20. For this purpose, we will use
the for..of loop, which is much more readable than the regular for loop. In Figure 4.23, we have
the code snippet that iterates over each of the objects in the movies array and prints the name and
director. We create a temporary variable to hold the current entry of the array in the loop and use
that variable to print the properties:
Introduction to JavaScript 97
We looked at some very useful examples of loops in this section. Let us move on next to conditional
statements.
conditions. It is important to remember that in the absence of an else statement, JavaScript ignores
the conditional code block when the if condition is not true:
Operator Description
== Equal to
=== Equal value and equal type
!= Not equal to
!=== Not equal value and not equal type
> Greater than
< Less than
>= Greater than or equal to
<= Less than or equal to
In the next section, let us learn about JavaScript functions and how to use them to make the code
more reusable.
Functions in JavaScript
Functions are used to package reusable code blocks to avoid redundancy. In JavaScript, the function
is declared using the function keyword, followed by its name, parameters, and body. A function
can accept zero or more parameters. Parameters must be separated by a comma if there is more than
one. Functions can also return a value using the return statement followed by an expression or
a value. Within the function, you can use the argument object to access the arguments as an array.
Figure 4.25 illustrates a function that computes the area based on the number of arguments sent:
100 Getting Started with the Basics
In the next section, let’s look at how and where to continue our journey of learning JavaScript.
e topics we have surveyed so far in JavaScript are a humble beginning and there are tons more to
explore in this topic. ECMAScript 6 was a huge upgrade to JavaScript, and it has provided various
ecient ways of performing routine programming tasks such as writing loops, dening functions, and
more. We will be learning some of these more eective and newer ways in the subsequent chapters
as needed. In the meantime, the MDN docs for JavaScript, located at https://developer.
mozilla.org/en-US/docs/Web/JavaScript, can be used as a standard reference to get
additional details on any concepts.
Summary 101
Summary
is chapter encompassed a considerable number of hands-on skills that a quality engineer uses
daily. We started the chapter by looking into the various aspects of selecting an IDE. We moved on to
downloading and setting up VS Code on macOS. We also learned how to search and use an extension
from the VS Code Marketplace. We commenced our JavaScript learning in the subsequent section by
understanding why we should learn it and laid a solid foundation with concepts such as variables and
data types. We then learned about string operations before getting introduced to JavaScript objects.
We dealt in detail with arrays and object literals.
We concluded our introduction to JavaScript by gaining knowledge about loops, conditionals, and
functions. We grasped a little more detail on Git topics such as commits and merge conicts. We
closed out that section by learning some additional Git commands.
is sets us up excellently for the next chapter, Test Automation for Web. You will use your gained
knowledge of JavaScript to automate a test using the Cypress tool. We will also look at the various
considerations for web automation.
Questions
1. What are some factors to consider when choosing an IDE?
2. What is the dierence between creating a variable using let and const?
3. How can we check whether an element is present in an array?
4. What are the advantages of object destructuring?
5. How are functions dened in JavaScript?
6. What does a git bisect command do?
7. What are some ways to avoid merge conicts?
8. Why is a git commit message important?
5
Test Automation for Web
Test automation for modern web applications poses tough questions for quality engineers regularly,
and there has been signicant progress in terms of the tools and support in recent years. e test
automation market is ripe with tools to aid engineers in setting up and executing ecient test scripts.
Some notable tools include Protractor, Cypress, and WebdriverIO. e development of these tools
with all their innovative capabilities is strong evidence of the evolution in the quality engineering
space, primarily to address modern web automation demands. In this chapter, let us dive deep into
automating a web application using Cypress and learn the nitty-gritty aspects of the tool.
Here are the main topics we will be looking at in this chapter:
• Why Cypress?
• Installing and setting up Cypress
• Creating your rst test in Cypress
• Employing selectors and assertions
• Intercepting API calls
• Additional congurations
• Considerations for web automation
Technical requirements
In this chapter, we will continue using Node.js (version 16.14.2), which we installed in Chapter 4,
Getting Started with the Basics. We will also be using node package manager (npm) to install Cypress
version 11.2.0. All the code examples illustrated in this chapter can be found under the ch5 folder at
https://github.com/PacktPublishing/B19046_Test-Automation-Engineering-
Handbook/tree/main/src/ch5.
104 Test Automation for Web
Why Cypress?
Cypress is a next-generation frontend test automation tool built for automating both legacy and modern
web applications. It also comes loaded with additional power to perform in-depth component testing,
mocking and stubbing API calls, and more. Our focus in this chapter will remain on exploring its
end-to-end (E2E) testing abilities. Cypress has grown versatile in the space of web test automation as
it comes packed with many handy tools that might need additional manual integration eorts when
using some of the other tools in the market. Rather than limiting itself as a browser automation tool,
Cypress comes as a comprehensive E2E testing framework to validate both backend and frontend
logic. It has a similar conguration for every frontend framework, thereby making the setup easy and
portable. It also has tremendous performance gains when compared with the test runtimes of other
commonly used E2E test frameworks.
Several continuous integration (CI) services such as CircleCI, GitHub Actions, and more have
specic modules that oer seamless integration with Cypress. Cypress also supports SDKs to scale
the test execution across platforms on the cloud. ere are also options to extend the behavior of
Cypress using innumerable plugins, available at https://docs.cypress.io/plugins/
index. Cypress thus brings enormous simplicity for its users in testing modern web applications,
and in doing so, boosts their productivity.
To start learning Cypress, you should be aware of advanced soware testing concepts. It is absolutely
vital to possess reasonable experience working with JavaScript. It is recommended to go through the
Introduction to JavaScript section from Chapter 4 of this book to understand the basics. It would also
help to have a good understanding of object-oriented programming (OOP) to assist with creating
a robust test automation framework using Cypress. Knowing all that Cypress has to oer and more,
it is a wonderful time to dive into the installation and setup of Cypress.
2. Let us next create an empty project to install Cypress and further explore its features. Run
npm init –y in an empty folder (preferably named app) in your local directory to create a
package.json le. Figure 5.2 shows the corresponding output with the contents of the le:
Note
npm init <initializer> is used to set up new or existing packages. If <initializer>
is omitted, it will create a package.json le with elds based on the existing dependencies
in the project. e –y ag is used to skip the questionnaire.
package.json is the primary conguration le for npm and can be found in the root
directory of the project. It helps to run your application and handle all the dependencies.
3. Execute npm install cypress in the root of our src/ch5/app project. is creates
a node_modules folder, which contains a chain of dependencies required by the package
being installed (Cypress). Figure 5.3 shows the output of this step, with package.json
showing Cypress installed. It is generally considered good practice to save the testing libraries
in the devDependencies section of the package.json le using the npm install
cypress --save-dev command:
106 Test Automation for Web
4. Create an index.html le in the root, as shown in Figure 5.4, to serve as the primary loading
page for our application. Also, create an empty index.js le:
5. Execute npx cypress open to open Cypress. is command opens the executable le
from the node_modules/bin directory. Figure 5.5 illustrates the output where the in-built
browser is opened:
6. Now, click on the E2E Testing option, which adds some conguration les to the repository,
and hit Continue in the next modal, as shown in Figure 5.6:
108 Test Automation for Web
7. In the next modal, select the preferred browser for E2E testing. I have selected Chrome in this
case, as shown in Figure 5.7, and it opens the browser in a new window:
is completes the installation of Cypress and gets it ready to a point where we can start writing
our own tests. In the next section, let us start working on our rst test and review some additional
congurations.
Instead of using the function keyword, we name it like a variable and use an equals sign to assign
it to the body of the function. Aer the parameters, we use a symbol called fat arrow (=>). In the
case of one-liner functions, we can further simplify them by removing the curly braces surrounding
the function body. We could also remove the return keyword, and it still returns the computed
value. If we have only one parameter, we could lose the parentheses around the parameters as well.
It would look like this: const addNumbers = number1 => number1 + 5. An example is
shown in Figure 5.9. is works very neatly in the case of array iterations. Let’s say we have an array
of movies, and we would like to iterate over them and print the names of all the movies. is can be
110 Test Automation for Web
We could also pass in the whole body of the arrow function instead of the name, as shown in Figure
5.11. ese are called anonymous functions since they do not have a name and are declared at runtime:
A key advantage of using callback functions is that it enables the timing of function calls and assists
in writing and testing asynchronous JavaScript code. ere are many instances in the modern web
application where there is a need to make external API calls and resume the current task rather than
wait for the external call to complete. Callback functions come in handy here to unblock the execution
of the main block of code. It is important to use callbacks only when there is a need to bind your
function call to something potentially blocking, to facilitate asynchronous code execution.
112 Test Automation for Web
With this additional knowledge about functions in JavaScript, let us now commence writing our
first spec.
Our rst test searches for the string quality in the search box on the home page of https://www.
packtpub.com/. en, it veries the search result page by looking for the Filter Results
string. Copy and paste the code from the https://github.com/PacktPublishing/
B19046_Test-Automation-Engineering-Handbook/blob/main/src/ch5/app/
cypress/e2e/search_title.cy.js GitHub link into the test le.
Let us now examine the structure of a Cypress spec.
We have started with a comment that describes what is being achieved in this spec. Cypress internally
uses the TypeScript compiler, and the reference tag is used to equip autocompletion with only Cypress
denitions. e beforeEach block, as the name suggests, runs before every it block. It usually
contains the prerequisite steps to execute the individual it blocks. Here, we use the visit command
to access the Packt Publishing website within the beforeEach block. en, the it block drills
down to which action is performed in the spec. If we end up adding more it blocks to this spec, the
visit command would be executed before the beginning of each it block. is is a simple spec
but it captures the necessary structure of a spec written in Cypress.
Next, let us examine how to execute our rst spec.
Using the command line to execute tests is always a quick and easy option. It usually helps when you
are not interested in looking at the frontend aspects of the test execution. e npx cypress run
-s cypress/e2e/search_title.cy.js command can be used to execute an individual
spec in Cypress. e –s ag stands for spec, followed by the name of the le. Without the –s ag,
the npx cypress run command would execute all the specs found in the current project. Figures
5.13 and 5.14 illustrate the output of the command-line execution of our rst spec. Figure 5.13 shows
the output of the CLI, with a listing of actions performed on the UI:
114 Test Automation for Web
Figure 5.14 shows a summary of the tests executed, with a breakdown of the results:
Next, let us next explore the visual test runner for executing our spec.
Cypress comes with an extremely insightful and detailed test runner and provides quite a bit of
debugging data for tests being executed. To utilize this mode, we can start with the npx cypress
open command, which opens up a series of modals. e rst modal requires the selection of the type
of test, as previously shown in Figure 5.5. e second modal, as seen earlier in Figure 5.7, provides
an option to select a browser against which the test can be run. e third modal lists all specs in the
project and shows some additional metadata about the specs and their recent runs:
Test execution begins when the user clicks on the test, as shown in Figure 5.15. is opens a new
browser that shows the actual steps being executed. e le pane shows the various frontend and
backend calls being made while executing this test. Figure 5.16 shows a view of the test execution.
Cypress oers a live-reloading feature out of the box using the cypress-watch-and-reload
package. Whenever there is a change in the code, the test is rerun automatically and the view, as shown
in Figure 5.16, reloads live:
116 Test Automation for Web
is view also allows users to view the stack trace of errors and provides options to navigate between
test runs and settings. e browser on the right pane can be used like any other browser window to
inspect and debug using the developer tools. Users are strongly encouraged to further explore the
features that this test runner has to oer.
In the next section, let us gain a deeper understanding of using selectors in Cypress.
case. e answer would be to employ the simplest one that uniquely identies the required element
on the DOM.
Cypress assists users here by providing a selector playground feature that automatically populates the
selector. Let us rerun our rst spec using a visual test runner and reach the execution page, as shown
in Figure 5.16. Now, refer to Figure 5.17 and click the circular toggle icon is opens the selector
playground where the user can type the selector or use the arrow icon for Cypress to automatically
populate it. Now, the user can use the browser to click on the required UI element and get the unique
selector right away. e user can also play around with other options and validate their correctness
by plugging them into the textbox:
To write ecient automation scripts, it is vital to know which selectors are reliable and perform better
in a given situation. Imagine a test automation project with 5,000 test cases and all of them nd a link
using the worst-performing selector, which has a lag of 50 milliseconds relative to the best-performing
selector. at would make the test suite slower by 250,000 milliseconds for every run. is would
impact feedback times immensely when considering hundreds of CI pipeline runs over a few days.
XPath selectors identify the target element by navigating through the structure of the HTML document,
while CSS selectors use a string to identify them. Direct CSS selectors using an element’s ID or class
usually perform better than XPath selectors. Using an ID selector is oen the most reliable way of
selecting an HTML element. It helps to analyze the elements to understand whether they are dynamic
and which selectors would be supported across dierent browsers, and based on that, decide on a
selector strategy. It usually takes a bit of troubleshooting to arrive at an ecient pattern of selectors
working for a specic application and a team.
Let us now learn about the available assertion options.
Asserting on selectors
Assertions give us a way to perform validations on various UI elements. ey are usually chained to
the command with selectors and work together to identify an element and verify it. should is the
primary function utilized on assertions, and it works with a myriad of arguments.
Let us update our rst spec to add some assertions. We have earlier used the contains function in
our spec to assert a partial string in the search results page. Figure 5.18 shows the assertions in action.
Next, we add an assertion on the Reset button to validate that it is disabled. In the following line, we
118 Test Automation for Web
get the navigation bar element by the id attribute and chain it with an assertion that validates the
class name:
Let us add another assertion before entering the search string to validate it is empty using the have.
value parameter. Figure 5.19 demonstrates this assertion:
e value of the static response parameter can be obtained using the Network tab of the developer
tools to get the actual response for the API call. is is illustrated in Figure 5.21. By passing this in as
the staticResponse parameter, the GET call on this URL will always return the stubbed response
instead of the original:
is empowers the user to test the underlying API calls for dierent payloads and validate the application
behavior in each case. is also saves resources in cases where some of these are expensive API calls.
is is just one way to handle API calls with Cypress, and there are a variety of options available to
explore. In the next section, let us quickly review some additional congurations that might be helpful
with setup and validation.
Additional configurations
Let us review a few additional congurations in this section to build stable and ecient specs:
• e rst conguration is a Git feature and not specic to Cypress. Adding a .gitignore
le is a general necessity for all projects. Add it to the src/ch5/app root folder to ignore
les we don’t want Git to track on our local directory. As shown in Figure 5.23, let’s add a
node_modules folder so that we don’t have to check in and keep track of all dependencies:
• Cypress comes with a default timeout of 4 seconds (4,000 milliseconds), and the get method
accepts a second parameter to set a custom timeout. For example, in our spec, we can add extra
wait aer searching for the string and waiting for the Reset button to appear with cy.get(.
reset-button, {timeout:10000}).should("be.disabled"). is line waits
for 10 seconds for the Reset button to appear and then runs the assertion.
• Cypress provides a delay feature when performing actions on the DOM. For example, when
typing an entry in the textbox, it has a default delay of 10 milliseconds for each key press. In our
spec, this delay can be customized as cy.get(".input-text").type(`${search_
string}`, { delay:500 }) to t the need of the application. In this case, there will
be a half-second delay before typing the next character in the textbox.
We have secured a solid understanding of the major features of Cypress and are well set to explore
its capabilities further. Before we close this chapter, let us review some valuable considerations for
web automation.
Limitations of Cypress
So far, we have reviewed in detail what Cypress can do, but it would be wise to also call out the
things Cypress cannot do as of today. When considering test automation at an organizational scale,
it is critical to gather clarity on how the tool ts in. Let us now list a few items that Cypress does not
support as of today:
• Always focus on validating the core business logic and the scenarios that surround it. Moving
past the basic functionality and building a stable automated regression suite for your web
application gives tremendous ROI in the long term.
• In the era of digitization, the usability of the web application takes a focal role, and it is
compulsory to validate the look and feel of the web application across multiple browsers on
multiple platforms.
• It is essential to perform due diligence regarding continued support from the community or
the vendors before deciding on a tool or strategy for web application automation.
• We can’t stress enough the critical role Agile methodologies play in modern soware projects.
So, it is vital for the web application tool to integrate seamlessly with CI services and perform
eciently in union.
• e data and privacy aspects of test data should be taken into account since modern web
applications tend to tap the power of cloud services continually. Further attention has to be
paid when handling personally identiable information (PII).
• To gain additional stability with test scripts, avoid cluttering them with brittle selectors. Exercise
caution when choosing a selector and have a long-term view of how the screen might change.
• Distinguish between synchronous and asynchronous calls within your web application and
employ test methods appropriately to suit the purpose.
• Make eorts to organize tests consistently for readability and performance reasons. Explore
the tool’s capabilities or additional plugins to standardize test scripts.
is brings us to the end of a detailed introductory walk-through of Cypress and its features. ere
is more to explore and learn, as with any other tool. Cypress oers great promise for web application
automation and provides innovative solutions to some of the problems that have haunted the test
engineering community in modern web application testing. e Cypress team actively releases a lot
of new features on a regular basis, and it is the right time to further explore its advanced abilities. Let
us summarize what we have learned in this chapter in the next section.
Summary
Let us quickly recap what we have learned in this chapter. We went through a step-by-step installation
and setup process for Cypress. We commenced the next section by understanding arrow and callback
functions in JavaScript. en, we continued on to write our rst spec and ventured out to comprehend
its structure and execution capabilities. We worked on using selectors and assertions within our spec
Questions 123
to identify and validate DOM elements. en, we learned how to intercept API calls in Cypress. We
familiarized ourselves with some additional Cypress congurations before taking on web automation
considerations.
In the next chapter, we will confront another crucial quality engineering topic: mobile test automation.
We will be using Appium 2.0 to formulate test scripts for Android and iOS platforms.
Questions
1. What are some advantages of using Cypress?
2. What is the purpose of the package.json le in the code repository?
3. Why are callback functions used in JavaScript?
4. What is the purpose of a beforeEach block in a Cypress spec?
5. How do you select a DOM element using the id attribute?
6. What is the Cypress command used to intercept API calls?
6
Test Automation for Mobile
e demand for releasing quality mobile applications across multiple platforms warrants a solid test
automation framework to thoroughly inspect and catch any regression issues. Mobile application
developers have the necessity to rapidly release bug xes and new features to keep up with the
competition. is makes mobile test automation indispensable in the development life cycle. In this
chapter, let us take a hands-on approach to thoroughly review mobile test automation and its setup.
Here are the main topics we will be looking at in this chapter:
Technical requirements
We will continue using Node.js, which we installed in Chapter 4. We need the Java Development Kit
(JDK) on our machines (which can be found at this link: https://adoptium.net/temurin/
releases) to download and install the compatible version with the operating system. Please
remember to set up the JAVA_HOME path in your .zshrc or .bashrc les. JAVA_HOME should
point to the directory where the JDK was installed.
Next, we will be needing Android Studio, which can be installed using the following link: https://
developer.android.com/studio. Similar to the JAVA_HOME path, the ANDROID_HOME
variable should be set up in your .zshrc or .bashrc les and point to the directory where the Android
SDK is installed. Also, make sure to append the PATH variable to include the platform-tools and
tools folders within the SDK. We will be using a demo Android application from github.com/
appium/android-apidemos for our automated testing. is is Google’s demo application used
126 Test Automation for Mobile
for testing Appium. All the code and setup used in this chapter can be found at https://github.
com/PacktPublishing/B19046_Test-Automation-Engineering-Handbook/
tree/main/src/ch6.
What is Appium?
Appium is an open source tool for automating native, hybrid, and mobile web applications. Appium
primarily operates on iOS/Android mobile applications and can support Windows desktop applications as
well. Appium uses vendor-provided frameworks under the hood—namely, XCUITest and UIAutomator
for iOS and Android platforms, respectively.
Appium wraps these vendor-provided frameworks into the WebDriver API. As we have seen in
Chapter 2, Appium uses a client-server architecture and extends the existing WebDriver protocol by
adding additional API methods to support mobile automation. For engineers who have previously
worked with WebDriver for web automation, this should be quite familiar and should not be brand
new. It supports multiple programming languages such as Java, JavaScript, Python, Ruby, and so on.
Now, let us review Appium’s advantages in the next section.
Appium installation
Next, let us go ahead and install Appium. is can be done using the npm install –g appium@
next command to install a version above 2.0 globally. e use of @next here is to force an installation
of a beta version (2.0.0). If by the time you install this, 2.0 is available as the latest stable version, you do
not have to use @next. With the appium –v command, double-check the version aer installation.
Appium involves multiple installations working in tandem, and it would be convenient to have a tool
that could provide us with constant feedback on the health of our setup. appium-doctor does
just that. Let us install it using the npm install –g appium-doctor command, and the
installation can be checked using appium –version.
appium-doctor can be executed for the Android platform through the appium-doctor
--android command. It primarily checks for the presence of all dependencies and their path.
Users should be on the lookout for any errors in the output from executing appium-doctor and
x them before proceeding further.
128 Test Automation for Mobile
ere is one more installation before we can wrap up this section. Let us now install the necessary
Appium drivers for iOS and Android using the following commands:
e installations can be veried using appium driver list, as shown in Figure 6.1:
is completes the Appium setup for macOS, and we have a couple more steps before we can start
writing our rst tests. Before diving into the WebdriverIO setup, let us look at how to congure an
Android emulator.
Setting up Appium and WebdriverIO 129
1. In the home dialog of Android Studio, click on the Virtual Device Manager option, as shown
in Figure 6.2:
2. e Android Studio installation usually comes with an emulator, as shown in Figure 6.3. You
can add another device by clicking on the Create device button at the top le of the dialog
box. is opens an additional dialog to set up the new hardware:
130 Test Automation for Mobile
3. For our example, let us select Pixel 4a and hit Next, which will take us to the System Image
selection dialog.
4. Please make sure to download two dierent versions here. We will be running the Appium
tests on one version and connecting the Appium Inspector on the other. In our case, we will
be downloading the Android API versions 32 and 33, as shown in Figure 6.4:
Setting up Appium and WebdriverIO 131
5. Hit the Next button and complete the emulator setup with the Finish button.
6. On the Device Manager dialog, hit the play button against one of the devices, as highlighted
in green in Figure 6.5. is will open the device emulator:
132 Test Automation for Mobile
We are now set up with Appium and an emulated device to test on. Let us now dive into WebdriverIO
installation and setup.
1. In the rst step, we will be selecting the location of the automation backend. Since we are not
running the tests externally yet, we will be selecting the rst option, which is the local machine.
We will be using the Mocha framework for our tests, and that option should be selected in
the next step.
2. In the next step, we will be selecting the No option as we will not be using any compiler in
our tests.
3. We will go with the default location for our test specs in the next step.
4. We will type No in the next step as we will be starting all our tests from scratch and do not
need the autogenerate option.
5. We will stick with the default spec reporter in the next step.
6. Let us skip adding any plugins at this step.
7. In the next step, since we will be running the tests from Appium, we will not be needing any
additional drivers. So, let us select the appium option.
8. We can ignore the base URL step as we will not be running a test on the web, and move on to
the next step.
9. In the last step, we can select Yes for running the npm install.
e use of the CLI to congure WebdriverIO is productive as we circumvent the need for installing
these packages manually. WebdriverIO does a lot of heavy liing for us to congure the fundamental
requisites for our project.
134 Test Automation for Mobile
Before proceeding, please make sure to install Appium and its drivers again within the webdriverio-
appium folder as this is where we will be storing and executing our tests.
In the next section, let us look at additional WebdriverIO conguration for Android.
We are now ready to update the capabilities section of the cong le. Refer to Figure 6.8 for the values
to be used here. We have added the platform name and platform version, which are Android and
13.0, respectively, in this case. en, we added the device name, which should be the same as the one
set up for the emulator in Android Studio. e automation name is the name of the driver used for
Android automation.
For the app path, we use the path library to dynamically create a complete path to the test app within
our project, as shown in the following screenshot. is library is built-in in Node.js and doesn’t need
to be installed separately. e path library must be initialized at the beginning of this cong le using
const path = require(path). is completes the preliminary customization of the cong
le for the Android application:
Setting up Appium and WebdriverIO 135
Before we try to run the app with WebdriverIO, let us create a test folder and an empty test le, as
shown in Figure 6.9. Also, launch the specied emulator from within Android Studio:
We are now ready to run this spec. For running this spec, use the npx wdio command. is
command by default uses the wdio.config.js le to spin up the Appium server, load the test
app, and execute the test. Results from the empty test can be seen in Figure 6.10:
136 Test Automation for Mobile
is conrms that our installation/setup is complete for Android, and we can go over the manual
conguration for the Appium Inspector tool.
In the previous section, we used an emulator to run automated tests with WebdriverIO. Now, let us
congure another emulator that can be used to nd elements on our Android application. Earlier in
this chapter, we added a virtual device within Android Studio, which was shown in Figure 6.6.
So, we already have two dierent virtual devices set up—namely, Pixel 4a and Pixel 3a. Now, let us
set up Pixel 3a on the Appium Inspector tool. We will be adding capabilities, as illustrated in Figure
6.12, under the Desired Capabilities section of the tool. Also, remember to update the port number
to 4724 since we are already using 4723 for running our WebdriverIO tests:
Next, bring up the Appium server on port 4724 using the appium –p 4724 command. Once the
server is up, hit the Start Session button on the Appium Inspector window to load our application on
the Pixel 3a emulator. Figure 6.13 shows the test application loaded simultaneously in the emulator
and Appium Inspector window:
Figure 6.13 Test application loaded in Appium Inspector and the emulator
In the next section, let’s understand how an async function works in JavaScript and then write a
test to validate mobile elements.
and its response are successful, then the promise is fullled, but if there is a network failure, then it
is rejected. We could dene specic behavior for each of these cases.
When the async keyword is used before a function, it always makes it return a promise. Similarly, the
await keyword used within the async function waits until the promise resolves. async/await
are essentially the syntactic sugar in JavaScript that let programmers write asynchronous code in a
synchronous manner. We will be using async/await keywords in the next section to write tests
in WebdriverIO.
Figure 6.14 shows an example of a simple function with a promise using async/await keywords. A
promise named simple_promise is being created, and it is set to be resolved aer a timeout of 5
seconds. e result of simple_promise is stored in the result variable, which is then printed
onto the console:
at was a very quick introduction to promises and JavaScript functions with async/await loops.
ere is denitely more to it, and these functions can get extremely complicated easily. We will just
be using a simple async/await loop in our WebdriverIO test in the next section. Let us now get to
writing a test for a mobile application.
140 Test Automation for Mobile
Let us now write a simple test to click on the Animation option and verify that the Bouncing Balls
option is displayed on the subsequent screen. e user can navigate to the menu within Animation by
using the highlighted Tap icon in Figure 6.15. We begin the test by capturing the Animation option
using its accessibility ID. e tilde symbol (~) is used for that.
en, we use the click () function to interact with the captured element. In the next menu, we
capture the Bouncing Balls element and verify its presence with the toBeExisting() function.
e test can be triggered using the npx wdio command:
Figure 6.16 shows the results of the test execution, with the Appium Inspector showing the selected
menu option:
Other selector options to explore are class, xpath, and elementId. When using these selectors,
users should be wary of their uniqueness and how concise they are. is completes our section for
Android mobile automation. We went through the installation and setup process and got to the point
where we are able to write our own tests. For further exploration of the various features that Appium
oers, refer to the documentation at https://appium.io/docs/en/about-appium/api/.
In the next section, let us survey a few key considerations for mobile automation.
Areas of complexity
Mobile automation poses certain challenges that are common across platforms. Let us examine them
one by one now:
• One of the major challenges is that a mobile application can be run on dierent devices from
distinct manufacturers on multiple versions of operating systems. A solid automated test strategy
addressing these compatibilities is a must-have.
• Usability testing to assure a consistent user experience across these platforms must be planned
and executed within the testing cycle rather than being an aerthought.
142 Test Automation for Mobile
• Testing for various geographical regions and cultures must be performed to verify the accuracy
and relevance of the mobile application.
• Every platform has its own native actions, and test automation should account for them and
design tests to verify them.
• Every mobile application must be thoroughly security-tested for possible threat and vulnerability
scenarios.
• Testing for a range of internet speeds and bandwidths should also be performed to verify the
stability of the mobile application in urban as well as remote areas.
• Mobile devices come with diverse screen resolutions, and it is the role of test automation to
validate that the application renders correctly in all of them.
• Test automation should consider the type of mobile application being tested. e test approach
for a native application that is designed to work only on a specic device should be dierent
from a hybrid application. For example, Progressive Web Apps (PWAs) are expected to work
on any device and therefore involve a more diverse testing eort.
Let us next review some iOS-specic factors that inuence test automation.
iOS-specific considerations
Creating automated tests for the iOS platform needs distinct installations and further setup. Let us
list here the various pieces that work together to write a functional iOS test:
• iOS has a separate development environment called Xcode, and this is used to spin up the
emulator’s specic iOS platform. is can be downloaded from the AppStore.
• Xcode Command Line Tools comes with many useful tools such as Apple LLVM, compiler,
linker, and Make for easy execution of soware through the command line:
Here is an example of the capabilities section of the wdio.config.js le for iOS:
platformName: "iOS",
"appium:platformVersion": "15.0",
"appium:deviceName": "iPhone 13",
"appium:automationName": "XCUITest",
"appium:app": path.join(process.cwd(),"/app/iOS/Test-iOS.app")
Key considerations for mobile automation 143
Let us look at the pros and cons of using emulators for automated mobile testing in the next section.
e chief aspect of mobile automated testing lies in choosing between emulators and physical devices.
You might say that testing against a physical device is more realistic, but it comes at a cost. At the
same time, testing with emulators has certain drawbacks. Let us explore the dierences in detail here.
An emulator is a soware program that simulates the hardware and operation of the mobile device.
Its main goal is to provide the user with an experience of using a real device. It is usually platform-
specic and is customizable to use dierent versions of the hardware and soware. One of the key
advantages of using emulators for test automation is their cost. eir easy availability also makes them
a viable option for testing. Unlike real devices, they also come with certain features to aid in testing.
eir main downside is in replicating certain performance issues such as battery life and network
connectivity. e test results in these areas may be unreliable. It also gets increasingly complicated
to test the device behavior when multitasking. is is where using real devices come in very handy.
Testing on real devices includes running automated tests in the same way the end users would use
handsets. e results in this case are highly reliable and can be eectively used to validate battery and
other performance issues. Using real devices comes with a high cost, though. Every model with every
upgrade must be bought and maintained in terms of both hardware and soware. Cross-platform
testing becomes impossible with real devices as the OS must be updated for every change. A good
mobile test automation strategy should include a combination of both real devices and emulators.
is gives the right balance for testing both functional and performance aspects of the mobile device
with its dependencies on the platform. Let us now look at how cloud service providers (CSPs) assist
in mobile test automation.
Choosing CSPs
Cloud-based mobile application testing provides the option to users to link with multiple mobile
devices at the same time. It is a key aspect of today’s mobile automation strategy. It enables us to
scale testing with ease while testing features across multiple geographic locations. Organizations can
choose to use a private cloud for their testing, which drastically reduces security concerns. Cloud-
based providers give you options to combine various versions of hardware and soware for testing.
Usually, the number of such combinations available to the users is in the scale of thousands. is
allows us to test and debug issues much quicker. Testing teams can focus purely on the functional and
performance aspects while leaving the device/emulator maintenance to the service providers (SPs).
is also avoids the cost of setting up an on-premise testing lab.
Some notable cloud providers are as follows:
• Sauce Labs
• BrowserStack
• LambdaTest
144 Test Automation for Mobile
• Kobiton
• AWS Device Farm
• Firebase Test Lab
ese providers have a predened subscription and oer several advanced built-in features to suit
testing needs. ey come up with a default test pipeline setup that can also be run in parallel to save
time. An important consideration while choosing a cloud-based provider is to review their quality
and security standards before entering into a contract with them. e cost of moving out of a cloud-
based mobile platform rises the longer you are with them. Let us review some ways to optimize our
mobile test framework.
Each of the cong les for the platforms will contain platform-specic information, as shown in
Figures 6.18 and 6.19. e corresponding sections should be removed from the shared cong le:
Optimizing our mobile automation framework 145
e Android cong le holds the path where the Android tests live and their platform-specic capabilities:
e iOS cong le similarly holds iOS-specic information. e port value remains the same in these
les, but it may change when executed using a cloud-based provider for these platforms. Another
change would be the way we execute these tests. Now that we have distinct cong les, we will run
them using the npx wdio config/wdio.android.conf.jscommand.
Another quick way to optimize our tests is by using hooks. Hooks are essentially reusable code that
can be run multiple times but dened only once. e commonly used hooks in WebdriverIO are
before, beforeEach, after, and afterEach. e before hook runs before the rst test in
the block, and the after hook runs aer the last test in the block. beforeEach and afterEach
hooks run before and aer each test in the block. Hooks can help reduce test dependency, which
in turn helps reduce code duplication. All prerequisites for a given block/test can be grouped into
before and beforeEach blocks. Similarly, all cleanup and teardown steps can be organized into
after and afterEach blocks.
is brings us to the end of this chapter. Let us quickly summarize what we have learned in this chapter.
Summary
In this chapter, we covered various aspects of mobile test automation. We started with understanding
what Appium and WebdriverIO are. en, we dived into their installation and setup in detail. We
learned how to set up and execute tests in WebdriverIO using Appium. While doing this, we also
absorbed how to use the Appium Inspector tool to nd elements and used it in our spec.
en, we moved to review certain key considerations for mobile test automation. In that section, we
surveyed the areas of complexity, understood the dierence between using real devices and emulators,
and investigated the advantages of using CSPs. Finally, we picked up a couple of ways to optimize
our test framework.
In the next chapter, we will be taking up the exciting topic of test automation in the API world. We
will be using the Postman tool to achieve that. We will also learn about using Docker containers to
execute our API tests.
Questions
1. What is Appium doctor used for?
2. What are the disadvantages of using an emulator for mobile testing?
3. Name some common challenges with mobile test automation.
4. What are the benets of using CSPs for mobile test automation?
5. How do hooks help in the test framework?
7
Test Automation for APIs
An application programming interface (API) helps two systems interact with each other over the
internet by implementing a set of denitions and protocols. APIs help tremendously to simplify the
design of soware systems and assist in opening up access to the system while maintaining control
and security over calls being made. APIs primarily act as intermediaries between various parts of the
application as well as with external integrations.
ere are three main kinds of API architectures—namely, REST, RPC, and SOAP. Each one of them
has its pros and cons. Diving deep into the types of APIs and their architectures is out of the scope of
this book. Instead, we will be learning about testing Representational State Transfer (REST), which
has been the most popular architecture for constructing APIs.
It is crucial to maintain the quality standards of APIs as they are oen the point of entry for various
external application calls. erefore, API testing becomes a fundamental part of the soware development
life cycle. ere are various testing tools available in the market for testing APIs, some of the notable
ones being Postman, SoapUI, Apigee, Assertible, and so on. Each of these tools comes with various
capabilities, and it is vital to choose the right tool that suits the needs of your organization. In this
chapter, we will be looking at API testing with Postman. Postman comes with plenty of built-in tools,
and most of them are available for free. ese are the topics that we will be covering in this chapter:
Technical requirements
We will continue using Node.js along with JavaScript in this chapter. We will also download the Postman
application (version 9.3.15) and the Newman command-line tool. We will need Docker installed
locally to run our Postman collections on a Docker container. Docker installation instructions can
be found at https://www.docker.com/.
e primary focus of API testing is to validate the business logic of APIs, while other types of testing
include performance and security. It involves the collection of test data to be sent in as JSON requests
to the API and validating the response for accuracy. Some of the items to look for in the response
are status, syntax, schema conformance, and functional correctness. API testing is much quicker and
Getting started with Postman 149
provides the benet of testing very early in the development life cycle. Let us now get started with
downloading and setting up Postman.
In the next section, let us look at how to work with workspaces in Postman.
150 Test Automation for APIs
We are creating a Personal workspace for this example. Private and Team workspaces allow adding
team members to the workspace by inviting them via email or by sharing the workspace link, whereas
a Public workspace can be accessed by anyone working with the Postman tool. e changes done by
the team members are synchronized in real time across the user accounts accessing the workspace.
Figure 7.3 shows the home page with multiple workspaces. Users can access the contents of these
workspaces on any device they log in to with their account credentials. us, workspaces promote
eective collaboration across the team:
Sending GET and POST requests 151
Let us now send our rst GET and POST requests using Postman.
In most cases, the API will have certain authorization to be added for the request to work. Postman
supports a wide variety of authorization mechanisms that can be accessed via the Authorization tab,
as shown in Figure 7.6:
154 Test Automation for APIs
Postman identies the applicable headers for a given API call, but in cases where there is specic
metadata that must be sent as part of the header, this can be done using the Headers tab. Postman
automatically identies any query parameters that are added as part of the URL. For the case in
Figure 7.7, https://api.agify.io?name=packt, a name is sent as a query parameter as
part of the URL. Postman creates a parameter in the Params tab, and this can be modied to feed the
request with dierent test data. New parameters can be manually added here as well:
Sending GET and POST requests 155
Users are encouraged to check out the various other features available within the request and response
windows. Let us now learn to make a POST API request.
Now, moving on to the Body section of the request, this API requires a name as a mandatory key for
the new repository being created. An example of this request can be found at this link: https://
docs.github.com/en/rest/repos/repos#create-a-repository-for-the-
authenticated-user. We will be using the raw body type with JSON from the dropdown, as
shown in Figure 7.9. Postman supports a wide variety of request body formats, and the one supported
by the API being tested should be used. On hitting the Send button, we complete the POST call to
the GitHub server to create a new repository with the name Packt-test-api-repo. Figure 7.9
shows the response status of 201 Created with all the metadata in the response body section. Users
may notice that the status code is dierent from the GET call as 201 indicates that in addition to the
call being successful, a new resource was created by the server:
Sending GET and POST requests 157
is completes our section on creating a new resource using a POST call. In the next section, let’s
learn about collections and how they help structure API requests in Postman.
Collections can thus help organize API requests in a meaningful way under a given workspace. is
helps immensely when there are a high number of requests, which is usually the case when testing
enterprise applications. Various other actions can be performed on collections, such as Export, Monitor,
Mock, and so on. Let us now look at one more feature of a collection that promotes collaboration
within the team.
Postman allows users to create a fork of a collection and merge it aer making some modications to
the forked collection. ese changes can be shared with other members, just like how Git pull requests
work. is can be done via the Collections drop-down menu, as shown in Figure 7.11:
Sending GET and POST requests 159
On clicking the Create a fork option, the user will be required to enter a label for the fork and to
which workspace this collection is to be forked, as shown in Figure 7.12:
160 Test Automation for APIs
Once the required changes have been made to the forked collection, a pull request can be created
using the Collections drop-down menu. Figure 7.13 shows a snippet of a pull request where the user
can provide a title, description, and select reviewers:
Sending GET and POST requests 161
e changes can be reviewed and merged using the merge option within the pull request or through
the Collections drop-down menu. is is a neat way to keep track of changes to your API requests
and nurture collaboration within the team while making these changes.
So far, we have looked at the basics of the Postman tool and how to make requests manually. is
works well for testing new API features but falls short when it comes to regression testing. In the next
section, let’s learn to write automated tests to validate API responses.
162 Test Automation for APIs
In the next section, let us review how to use snippets to speed up our test automation process.
pm represents a Postman object, and it contains all information pertaining to the request and response
body. e pm object comes with a lot of properties and methods built in. Here, we use the test method,
which accepts a description and a function within which an assertion can be dened. ese assertions
are dened using the chai library, and readers can refer to their documentation at https://www.
chaijs.com/api/bdd/ to get familiarized with more assertions.
Let us now add the Status code: Code name has string snippet, which adds the following
code snippet. In the case of a GET request, this string is OK, and for the POST request, it is Created,
as we have seen before:
Postman provides a snippet to validate the response time of the API. On adding the Response
time is less than 200ms snippet, we see the following code added. Note that we use the
expect assertion here, which operates on the responseTime property and checks its value range:
Let us now add an assertion on the response header using the Response headers: Content-
Type header check snippet. is can be further modied to check the presence of any header
in the response, as shown in the following code snippet:
Figure 7.14 shows a summary of the test results for the GET repository API call with a test status for
each of the snippets we have added:
ese are some of the generic tests we can add for API responses. In the next section, let us learn how
to add assertions on specic values such as the repository name on the response.
Postman has ve types of built-in variables, which are the following:
• Global variables: Variables with the broadest scope and can be accessed anywhere in a workspace
• Collection variables: Variables scoped to be available for all the requests within a collection
• Environment variables: ese variables are accessible only within an environment and primarily
used to manipulate access—for example, in staging versus production
• Data variables: ese are variables created when importing external data and are scoped for
a single execution
• Local variables: Used on tests in a single request and lose scope as soon as the execution ends
Writing automated API tests 165
Let us consider the API for creating a new GitHub repository to understand how variables can be
used in Postman to remove static context from API requests. For example, we must validate that
the repository name matches between request and response. It is also important to remember that
GitHub repositories cannot have duplicate names. So, in order for this to work, we should provide a
randomly generated name in our POST request body and validate the presence of this name in the
corresponding response body. Dynamic variables come in handy to achieve this in Postman. Variables
are dened using double curly braces: {{<variable name>}}. e request body for the create
repository POST call will look like this:
{
"name": "{{repository_name}}",
"private": false
}
Now, we need this value to be new for every POST request we send, and the best place to do this is
in the Pre-request Script tab of the request dashboard. is represents a pre-condition to the test
case, and it is run before the request is sent to the server. We accomplish random value generation by
dening a variable with static and dynamic parts. Here, we use the variables property of the pm
object. en, we set this as an environment variable. Figure 7.16 shows a new repository_name
environment variable created in the current environment, Packt testing:
Note
Pre-requisite scripts are run before the API request is executed, while the test scripts are run
aer the server returns a response.
166 Test Automation for APIs
So far, we have created an environment variable in the Pre-request Script tab and updated the request
body to use that variable. Let us next add an assertion on this variable in the response body. is can
be done in the Tests tab via the Response body: JSON value check snippet. is snippet
helps check a specic value in the API response. Note that the value of an environment variable can
be fetched using pm.environment.get("repository_name"):
In the next section, let us learn to chain a series of API requests by passing data from one API to the next.
We use the JSON.parse() method to convert responseBody into a JSON object and then
create an environment variable using the login key from the response. GET and DELETE calls both
use the https://api.github.com/repos/:owner/:repo route. We create requests for
each of these API requests with this route, and on saving, Postman automatically creates a new Path
variables section in the Params tab of the request dashboard. We can now substitute the captured
environment variables as values, as shown in Figure 7.17. In this way, we are chaining the response of
the create repository call to the GET and DELETE calls:
Writing automated API tests 167
On executing these requests one aer another, we notice that the values from the request are being
passed on to the next one, seamlessly eliminating static data transfer. is behavior makes Postman
an eective tool for testing complex API workows.
We now have a simple collection with multiple API requests, and it is not feasible to run each of them
manually for every test cycle. In the next section, let us survey a few ways of executing tests in Postman.
Using the Iterations option, users can specify the number of times the requests would be run. e
Delay option helps to add a specied wait between subsequent requests. is is very useful in case
of long-running requests. ere is also an option to upload an external data le and use that data in
the form of variables within the request. On clicking the Run button, all requests in the collection are
run, and results with a clear breakdown are populated in the same window, as shown in Figure 7.19:
Writing automated API tests 169
Postman also supports running a collection from the command line through a tool called Newman.
Newman can be installed using the npm command: npm install –g newman. e installation
can be veried using the newman –v command. To run the collection, we will rst export the
collections and the associated environment variables. A collection can be exported and saved to the
local lesystem using the Export option from the Collections drop-down menu. Similarly, environment
variables can be downloaded by using the Export option within Environments on the le navigation
bar. Note that these les are downloaded in a JSON format. Now that we have the collection and its
necessary variables, we can run it using Newman:
Postman provides integration with Docker for executing tests within a Docker container. Docker
is a platform that assists in building, deploying, and testing your application code on units called
containers, irrespective of the underlying operating system. It provides great portability for developing
and testing applications. Running a collection on Postman’s Docker container involves just a couple of
commands. Once you have Docker installed on your machine, run the docker pull postman/
newman command. is command pulls the latest image of the Postman docker/newman runner
from Docker Hub and sets up the container. Next, we need the URL of the collection to be able to run
it externally. is can be obtained using the Share option from the Collections drop-down menu.
Now, run the following Docker command:
is brings us to the end of a basic exploration of API testing with Postman. e Postman tool has
so much more to oer, and its capabilities can be referenced at https://learning.postman.
com/docs.
In the next section, let us review the considerations that go into API automation testing.
• Static data references must be eliminated wherever possible. ese render the tests inextensible
and isolated.
• Do more than happy path testing since API tests are quick to run and can provide feedback
early in the product life cycle. Applicable product use cases should be tested to a greater extent
via APIs. Consider mocking and stubbing to ll in gaps to complete the application ow.
• Since there is no frontend to check the test results, it is imperative to keep API tests clear with
sucient documentation. is helps especially in debugging when there are new failures in
the system.
• Manage the data needed for a test by employing setup and teardown tests wherever possible.
is helps clean up the environment before and aer the execution.
• Pay special attention to authentication mechanisms and try to implement these the same way
a real user would access the API.
172 Test Automation for APIs
• Add extra checks for data consistency when chaining responses of multiple services. Passing
the same data in dierent ways may not look bad at the API level but might end up breaking
the UI layer of the application.
roughout this chapter, we examined the requests and responses of REST APIs. As we saw earlier,
REST is an architectural framework for creating and accessing APIs. In the next section, let us review
and compare the testing aspects of GraphQL with REST.
• Tests on GraphQL should include schema validation while REST demands endpoint validation.
• Aer the initial learning curve, changes can be done faster in GraphQL APIs due to its client-
driven architecture. Test automation cycles must be designed to keep up with these rapid changes.
• Validations on API output should be customized to the specic GraphQL query being tested.
is is dierent in the case of REST with its xed response on endpoints.
• GraphQL was designed to ease API integration bottlenecks, while REST provides a solid
foundation for individual API designs. A higher eort may be involved in testing individual
GraphQL APIs while REST simplies isolated API testing.
GraphQL is a very detailed specication on its own, and readers are encouraged to go through the
documentation for further exploration.
is brings us to the end of this chapter. Let us now quickly summarize what we learned in this chapter.
Summary
We acquired a basic understanding of REST APIs and went through a basic setup of Postman with
workspaces. We looked in detail at sending GET/POST requests and how to validate their responses.
We then learned what collections are and how they help organize API requests within our workspace
for conciseness and collaboration. In the next section, we learned how to validate responses in an
automated fashion using snippets. We gained an understanding of how variables are used in Postman
to chain API requests. Subsequently, we surveyed various ways to execute collections. Finally, we took
up some key considerations that go into automating API tests and familiarized ourselves with how
GraphQL APIS are dierent from their REST counterparts.
In the next chapter, we dive deep into performance testing with the JMeter tool.
Questions 173
Questions
1. What are common areas to focus on in API testing?
2. What are collections in Postman?
3. What are snippets and how do they help?
4. How can complex workows be tested in Postman?
5. What is Newman used for?
6. What is Docker and how does it help?
7. What is GraphQL and how is it used?
8
Test Automation
for Performance
Performance testing ensures the speed, stability, and scalability of a soware application and helps
to verify the behavior of an application in various possible user scenarios. Even with considerable
technological advancements, many soware applications fail to produce the desired performance for
users during peak trac. erefore, it is imperative that performance testing is done early enough
in the application life cycle to provide critical feedback to the stakeholders and to maintain usability
at elevated levels.
ere are various performance testing tools on the market to choose from, and each one has its own
capabilities. Some examples are JMeter, LoadRunner, and Kobiton. In this chapter, we will be working
hands-on to gain an understanding of setting up and running performance tests using JMeter. ese
are the main topics we will be looking at in this chapter:
Technical requirements
To get functional with JMeter, we need Java installed on our machine. Currently, JMeter works with
JDK 8 and JRE 8 or higher.
Installing JMeter
Let’s look at the steps involved in the installation of JMeter:
1. e rst step in the installation of JMeter is to check the Java version on your machine. is
can be done using the java -version command. As shown in Figure 8.1, this command
prints out the JDK version:
2. e next step is to download the JMeter binary. e le for download can be found on the
JMeter website, https://jmeter.apache.org/download_jmeter.cgi. In this
case, I am downloading the binaries zip le for version 5.5, as shown in Figure 8.2.
Getting started with JMeter 177
3. Once the download is complete, move the zipped le to the desired local folder and unzip it.
is should create a new folder in the same location within which all the contents are extracted.
JMeter can now be started with the sh jmeter.sh command from the bin folder of the application.
is brings up the application in a separate window, as shown in Figure 8.3.
JMeter comes with a simple GUI that contains the following components:
• Menu bar: Contains a collection of high-level options to set up and congure various aspects
of the tool
• Tool bar: Contains frequently used tools
• Test plan tree view: Groups all components that are added within a test plan
• Editor section: Provides options to edit the selected component from the test plan view
In the next section, let’s look at how to create our rst performance test in JMeter.
Automating a performance test 179
We use a combination of three parameters to achieve the required pacing for our performance test:
ere are additional settings to congure and ne-tune the load on the test, as shown in Figure 8.5.
e next step is to add a sampler to the test plan. A sampler is nothing but a test added in JMeter.
Figure 8.6 shows the list of the samplers supported by JMeter. Let’s now add a simple HTTP sampler
for our test. We can then use the HTTP editor to congure our test.
Automating a performance test 181
e test plan can now be saved to a local directory using the Save option from the menu bar. e
next step is to add a listener, which helps us view the test results. A listener is a component within a
test plan that stores and allows us to views results. Let’s add the View Results Tree and View Results
in Table listeners to our test plan. JMeter provides a variety of listener options in the Add | Listener
menu. Figure 8.8 shows our test plan with the listeners added.
Automating a performance test 183
Aer saving the test plan, we are ready to execute our rst test. is is done using the Start button
on the menu bar. We can see the results being populated in the listeners as soon as the test begins.
Figure 8.9 shows a breakdown of the test run stats by the thread group within the View Results in
Table listener.
JMeter provides options to congure the elds in the results. Some important elds to look out for in
the results are Sample Time(ms), Latency, and Status, as they specify the status of the test and the
time taken to get a response from the server. JMeter oers a convenient option to save and view the
test results in CSV or XML format.
Let’s update the Response Assertion to look for the response code 200 and the Duration Assertion to
ag responses over 1,000 ms. ese conditions are checked aer every iteration of the HTTP sampler,
and the results are agged accordingly. Figure 8.11 demonstrates the execution of the Duration
Assertion where some of the responses took over a second to complete.
e Assertion Results listener is an eective component that collates the responses from all the assertions
so you can view them in one place. is listener can be added at the test plan level, as illustrated in
Figure 8.12. It combines the results from the Response Assertion and the Duration Assertion.
186 Test Automation for Performance
Let’s now look at how to use the command line to handle JMeter’s tests.
Here, -n stands for non-GUI mode, -t species the location of the test plan, and –l is the location
of the result logs. e command line supports various other parameters, but these are the minimum
required parameters to trigger the execution. Figure 8.13 shows the execution of a command line run.
Additionally, the sh jmeter –h command can be used to review all the available command-line options.
Performance test results can get voluminous, and it is always necessary to produce a clear and concise
report. It will be hard to understand the test results with just the results shown on the command
line and it necessitates a better report. is is achieved by using the –e option, which generates a
dashboard report, and the –o option to specify the location of the results folder. Figure 8.14 shows a
part of the HTML report generated when using these parameters. By default, this is produced as an
index.html le within the results folder specied as part of the command-line option. e full
command to achieve this is as follows:
Another powerful feature that the JMeter command line provides is the use of built-in functions to
send dynamic parameters when running a test plan. For example, in our test plan, we have hardcoded
the path as /terms-conditions. In real time, we would be testing dierent paths from the
command line and would not have to update the test plan for every run. e test plan can be updated
with a function in this eld to be able to receive this parameter via the command line using the format
${__P(VariableName)}. e path can now be sent through the command line by prexing J
to the variable name:
In the next section, let’s look at how to use the HTTP(S) Test Script Recorder component in JMeter.
Automating a performance test 189
We will also need a recording controller to be added to the test plan to categorize the recording by the
trac or per page. For simplicity, let’s use a single controller here, but in real-world scenarios where the
user ows involve multiple pages, we might need a separate controller per page. e Target Controller
property should be set to point to the right controller within the HTTP Test Script recorder. Another
notable feature within the HTTP Test Recorder component is Request Filtering. A lot of resources
are exchanged when recording HTTP requests, and not all of them will be applicable for load testing.
URL patterns that need to be included or excluded can be specied using the Request Filtering option.
e next step is to congure the proxy on our browser so that only the desired trac ows through the
port. is is done by specifying the default JMeter port 8888 within the browser’s proxy conguration.
Figure 8.16 shows this conguration on the Chrome browser.
190 Test Automation for Performance
ere is one more step before we can start recording, and that is to add the JMeter certicate to the
browser. is le (ApacheJMeterTemporaryRootCA.crt) can be found in JMeter’s bin
folder, and it needs to be added to the browser certicates via settings. Once this is done, we can
use the Start button on the recorder component to commence the recording. When the recording is
complete, the HTTP requests are stored under the corresponding controller. ese requests can then
be played back with the simulated load.
We have gained foundational knowledge on how JMeter operates, and we recommend you to further
explore the tool using the user manual at https://jmeter.apache.org/usermanual/
index.html. Let’s move on to the next section to gain a basic understanding of the Java programming
language and how to use it to write custom code within JMeter.
can be utilized in cases such as these to get the job done. Both these components support Java code,
and hence it is important to acquire basic Java knowledge. In this section, let’s go through a quick
introduction to the Java programming language.
package ch8;
public class first_java_program {
public static void main(String[] args) {
}
}
Let’s familiarize ourselves with these keywords, to begin with. Whenever a new class is created in
Java, the very rst line is usually the package name, followed by the class denition. e public
keyword is an access modier that denotes the access level of this class. is is followed by the class
keyword and the name of the class. Within the class, there is always a main method with a public
access modier.
is is followed by another keyword, static, which signies that this method can be invoked
directly without the need to create an instance of the class. e main method is always called by the
JVM at the beginning of program execution, and that is why we do not need an instance of the class
to call this method. Next is void, which represents the return type of this method. In this case, we
do not return anything and hence leave it as void. We could return a string or an integer depending
on what is being done within the method. e values within the parentheses aer the method name
mark the arguments accepted by the method.
Let’s add a simple print statement, System.out.println("My first java program")
within the main method and run it via the IDE. is should print the text specied within the
println method. is completes our rst program in Java. Java is a strong object-oriented language,
so let’s learn how to create classes and objects in Java.
Object-oriented programming primarily helps us model real-world information in our programs.
Let’s take an example of a bank account and see how it can be modeled in Java using object-oriented
techniques. To start with, let’s create an Account class, as follows:
package ch8;
192 Test Automation for Performance
is class would act as a template for all the accounts that are created. Each account created from
this template would be an object, or an instance, of this class. We have used dierent variable types
to model real-world information. We have also used the test_minimum_balance method to
derive and set the value of a variable called maintains_minimum_balance within the class.
Let’s now go ahead and create another class that holds these objects:
package ch8;
}
}
We have created two objects in our second class, which represent two dierent people’s bank accounts.
is example demonstrates how we can use classes to model information.
is section was meant to quickly inform you what the Java programming language is and how to write
a basic program. You are encouraged to refer to the ocial Java documentation at https://docs.
oracle.com/javase/tutorial/getStarted/index.html to further your knowledge.
Let’s now get back to writing custom scripts in JMeter.
One of the top uses of employing custom scripting within JMeter is to enhance the logging capabilities
wherever needed. is helps tremendously in reducing debugging eort. For example, the statement
log.info("Output from the log message") can be used to print additional logging
messages. Now consider the following code block, which can be run as part of the JSR233 assertion:
if ((thread_run_time+thread_latency)>response_threshold){
AssertionResult.setFailure(true);
AssertionResult.setFailureMessage("Threshold exceeded");
}
SampleResult is a built-in JMeter object through which various properties of the test result can be
accessed. Here, we are getting the run time and latency of the HTTP response and using an if statement
to perform an assertion. Custom scripting thus extends JMeter’s ability to perform specic validations.
Another area where custom scripting can be used is with getting and setting values of variables and
properties. It might be necessary to dynamically change the value of a variable based on the test result.
is can be performed with the following statements:
failure_count = vars.get("failure_count");
Failure_count++;
vars.put("failure_count", String.valueOf(failure_count));
Considerations for performance testing 195
We are getting the value of the failure_count variable and incrementing it before writing it out.
As you can see, custom scripting opens up various ways to extend our tests to address project-specic
needs. is is as far as we can go here; it’s up to you to explore it further.
In the next section, let’s explore some considerations for performance testing.
• Distributed load testing: Load testing should mimic the real-world user load, and it is vital
to distribute the load across multiple machines/servers to uncover critical bugs or memory
leaks during the testing phase. is can be done in JMeter by employing a local JMeter master
machine with remote slave machines.
• Managing resource requirements: e memory and resources of the load testing tool have
to be managed eectively to prevent false negatives in the test results. Running through the
command line, disabling memory-consuming parts of the testing ecosystem, and optimizing
test data are some rst areas to look into.
• Performance testing metrics: It is critical to review and agree upon a standard set of metrics
for all the applications in your organization. is helps you standardize your test results.
• Gradual performance degradation: Soware applications may experience a gradual decrease
in throughput due to a certain code block or a faulty conguration. ese issues are usually
not exposed by a single load or stress test. erefore, it is critical to run regular and prolonged
load tests based on the application’s needs.
• Performance test environment: e environment where the load tests are run should be
analyzed and set up to mimic the production environment as closely as possible. Hardware,
soware, and network congurations should be taken into account when you are coming up
with a performance test plan.
• Constant feedback loop: Performance testing should lead to a constant loop of performance
engineering to remove bottlenecks and improve user experience. Any time a major code
change is introduced, selected performance tests have to be executed and the results have to
be reviewed with stakeholders.
is brings us to the end of this chapter, and it should help you quickly get up and running with your
performance tests. In the next section, let’s summarize what we have learned in this chapter.
196 Test Automation for Performance
Summary
We commenced this chapter by discussing what JMeter is and how it works, and then proceeded to
download it. We ventured on to write our rst performance test by utilizing various components within
JMeter’s test plan, such as thread groups and HTTP requests. We then learned how to use assertions
to perform validations on the response. Subsequently, we looked at how to run the same test plan
via the command line and explored using the command line to generate detailed HTML reports. We
glanced through the HTTP recording capabilities of JMeter, and in the next section we dived into
custom scripting by going through a quick introduction to Java and how to use a JSR233 assertion.
We concluded the chapter by looking at performance testing considerations.
Questions
1. What is JMeter and what is its primary use?
2. How do you simulate user load in JMeter?
3. Why is the command line preferred over JMeter’s GUI for test execution?
4. Why is custom scripting needed in JMeter?
5. What is distributed load testing?
Part 3:
Continuous Learning
In this part, we will understand the Continuous Integration (CI)/Continuous Delivery (CD)
methodology and how several types of testing t into the CI/CD paradigm. We will also explore the
common issues and pitfalls encountered in test automation. By the end of this part, you will emerge
more condent in dealing with practical test automation matters in the current quality engineering
landscape.
is part has the following chapters:
• What is CI/CD?
• Test automation strategies for CI/CD
• GitHub Actions CI/CD
Technical requirements
We will be working on GitHub Actions in the last part of this chapter to implement a CI job. e
repository used will be https://github.com/PacktPublishing/B19046_Test-
Automation-Engineering-Handbook. It is advised to possess a basic familiarity with the
GitHub UI and how it works to follow along.
What is CI/CD?
CI/CD soware engineering practices allow us to automate the building and testing of code to
validate it meets the specications. Aer all the tests have passed, they equip the teams with options
to automate the delivery of code. Continuous Integration, Continuous Delivery, and Continuous
200 CI/CD and Test Automation
Deployment together signicantly reduce the time it takes to deliver application enhancements while
the engineering team can solely focus on product and code enhancements. Figure 9.1 illustrates how
these processes work in tandem to elevate soware delivery levels:
Let us take a quick look at the CI/CD process in the next section.
CI/CD process
CI/CD methodologies and the associated systems take a big leap in terms of soware quality
improvements than any other technology has done in the recent past. Automated tests are run as part
of the CI system every time a code or conguration change is made and thus serve as a comprehensive
regression test bed. Modern CI systems can not only execute tests that check functional behavior but
also validate the performance and security aspects of the soware application. A well-implemented CI
system inspires good development practices by providing constant feedback. One of the great benets
of CI systems is the visibility they provide the entire team into the release and feedback process. Any
member can visualize the progress and view failures with just a click of a few buttons.
e CI/CD process starts when the developers commit their code changes into Git. e CI system picks
up this change and triggers a new instance of the pipeline. At this stage, the code gets compiled, and
the rst set of tests (unit and component) are run. Code linting tools and code coverage analysis tools
are also run at this point. If the build and tests pass, then a merge request is created by the developer
to get feedback from the team. Aer this code review feedback cycle, the developer merges the code
to the main/master branch, which triggers the unit/component tests again. Additionally, the code
artifact created as part of the build process gets deployed to the subsequent test environment. is is
where smoke and end-to-end (E2E) tests are run to validate business scenarios involving multiple
services and/or UIs. is feedback loop continues until the code nally gets deployed to the production
environment where additional tests may run.
Let us dive deep into CI in the next section and understand its nuances.
What is CI/CD? 201
CI basics
CI addresses soware integration problems eectively and eciently. As the application under
development becomes complex and the code base involves multiple components, it is vital to get
feedback at every code change. e CI development practice enables engineers to integrate their work
frequently and detect errors instantly through code compilation and building, and running unit tests.
Each engineer usually commits at least once a day and hence encourages breaking down big changes
into logical chunks of code. Building and testing of the product oen occur numerous times a day in
an automated manner leading to a much higher condence level in the state of the project.
Figure 9.2 illustrates the major parts of a CI system. e CI server typically keeps polling the version
control repository every minute or so and runs a precongured build script by fetching the latest
version of the source les. e CI soware has a dashboard and oers options to kick o various
stages of the build process at will. e CI soware is also capable of messaging the stakeholders of
the current build via emails and/or instant messaging platforms. It is generally considered a good
practice to perform database setup as well as part of the CI build script to ensure the coherence of
the whole soware application:
Some of the good development practices that result from implementing a CI system are as follows:
CI systems eciently enable compiling and building of source code once and deploying it to multiple
environments. Even though the build’s congurability may vary by platform, the CI process eectively
remains the same. e usual practice is to execute the same build script against an environment-specic
properties le. is makes sure we release usable soware at any time and to any environment. is
is a tremendous advantage and takes a lot of manual eort without CI systems in place.
Implementing a CI system in existing projects is usually a daunting task as the team may feel they
have to go modify numerous processes they have been comfortable with over a period of time. It is
critical to educate the team about all the extra time they gain by not performing repetitive build tasks
and the overall increase in visibility from integrating individual changes into the code base.
As you may have noticed, the role of a quality engineer in the overall CI process appears minimal. But
it is not so. It is vital for a quality engineer to constantly review the automated tests run as part of the
pipeline to enhance coverage and reduce akiness. is also gives quality engineers an opportunity
to get involved early in the build and deployment process at every change. A quality engineer is also
responsible for establishing the right quality mindset in the team. When there is a failure in the CI
pipeline due to functional or E2E tests, it is oen a quality engineer who responds rst, debugs the
failure, and logs a defect if necessary.
is brings us to the end of this section on CI. Let us next review in detail CD and the deployment
pipeline.
Every code or conguration change introduced runs through the same set of processes, and by the
time it is deployed to the production environment, we can be sure that:
As appealing as it may sound from the outside, implementing a CD process is daunting and takes the
eort of many teams working in unison. e key lies in examining and understanding the existing
deployment system, breaking it down into simple and repeatable steps, and using the latest technologies
to automate it. It can be done incrementally so that over time, it evolves into a rened and ecient
system.
204 CI/CD and Test Automation
One of the central aspects of the CD process is to automate the acceptance tests to be executed as
part of the deployment pipeline. ese acceptance tests may be E2E UI or API tests. ese have the
signicant advantage of blocking a build that has failed a key business specication to be deployed to
production or even a production-like environment. By updating the automated tests consistently for
every code change, the tests ascertain that the candidate build delivers the intended value to the end
users. A common drawback with running automated acceptance tests as part of the pipeline is that
they take too long to complete for a single merge to the master. is is mainly because the underlying
application and all of its conguration have to be built and deployed before any of the pre-requisite
steps for the tests can be run. is adds time to the overall acceptance test cycle when the test run times
are included. It is common for projects to have acceptance tests that run a few minutes to multiple
hours, but there is always room for increasing the eciency of the automated tests. Quality engineers
and soware development engineers in test (SDETs) should always be on the lookout for ways to
refactor their tests eectively to reduce the overall deployment pipeline runtimes.
Another major advantage of the CD process is its capacity to validate certain non-functional
requirements (NFRs) as part of the deployment pipeline. It is not uncommon to unearth architectural
discrepancies in the late stages of a project life cycle, the reason being the nature of the NFRs themselves
and also the availability of all the components to execute sensible tests against them. is challenge
can be addressed through CD by including tests that validate certain performance thresholds for the
application as part of the CI pipeline. It is not possible to design an extremely performant and scalable
application at the inception of a project. But having these tests provides an initial comfort level with a
code change, and if there are considerable performance impacts, further load tests can be performed
in a full-edged performance environment to identify the bottleneck.
ere should be additional considerations made in terms of security and data compliance when
working with cloud platforms. It is a good practice to include cloud network connectivity and security
tests that run at regular intervals as part of the CD process. is ensures that the components are all
connected and working together in a holistic cloud environment in a secure manner.
CD involves not just the collaboration between engineers and the infrastructure team but demands
support from product owners/managers, executive sponsors, and everyone involved in between. It is
a paradigm shi and the new norm in the soware delivery world. In the next section, let us take up
some considerations for test automation in the world of CI/CD.
can be utilized in other areas. It goes without saying that building an accurate and reliable soware
application is possible only by establishing quality right from the lowest building block. Let us start
by looking at unit and component tests.
Unit/component tests
Unit tests verify the behavior of the smallest blocks of code, usually a single class or an object, whereas
component tests exercise larger blocks of code involving multiple classes/objects. Both these tests have
minimal external dependencies and oen involve mocking of objects that are outside the validation
logic of the test. ey are usually the fastest to run and hence provide the quickest feedback. All unit
and component tests should be run as part of the CI pipeline, and the recommendation is to run them
on every commit to the branch and on every merge to the master branch. is paves the way for
quick and ecient debugging when a failure occurs due to change. It also gives engineers the much-
needed condence that their changes work in tandem with other components upon merging the code.
Let us next take a look at API tests.
API tests
API tests, as we have seen earlier, verify the functional correctness of API endpoints. ese tests focus
mainly on the business logic of the API as opposed to unit tests, which deal with much smaller units
of code. API tests should be automated and run as part of the CI pipeline as much as possible on every
merge to the master branch. Since the advent of microservices, it has become a common practice to
break down business logic into multiple microservices, each containing a collection of API endpoints.
Each microservice essentially has associated API tests that should be run on every code merge into
the repository. is lays a perfect foundation for a wider test coverage for the core business logic and
running these as part of the CI pipeline rapidly ags alterations to the existing business logic.
Running API tests for a specic microservice in a CI system is a ripe ground for using containers as
these tests do not demand the presence of all dependent services. Dependent services, if any, can be
mocked to ensure the continuity of the tests.
Next, let us take up how E2E tests can t into CI pipelines.
UI tests in general tend to be brittle when compared to API tests, and it is essential to hand-pick a
selection of E2E tests to run in the context of CI. Long-running CI pipelines can damage an engineering
team’s productivity, and hence it is crucial to include only stable tests. Running these tests on every
commit or build could spell disaster, and it is mandatory to monitor and optimize the CI pipeline’s
runtimes whenever an E2E test case is added to the test suite.
Let us next look at smoke tests and how they can be utilized in a CI system.
Smoke tests
Smoke tests do not address a specic architectural component; instead, they focus on delivering a
clean build. Smoke tests are a collection of test cases that are run at the end of a deployment job to
give condence in the quality of the build. ey are selected based on the business use cases and
workows in the application and verify they work as per the specications on every deployment to an
environment. Smoke tests are a combination of E2E API/UI and component tests. ough minimal
and conservative, there are smoke tests that can be run against the production environment. Major
CI/CD systems and test automation frameworks provide features such as tagging that help ag smoke
tests with ease. Additional precautions have to be taken to organize environment-specic variables
in the CI/CD system if the same smoke test suite is designed to run against multiple environments.
Table 9.1 summarizes the content discussed in this section:
Figure 9.4 illustrates how a CI/CD system incorporates constant feedback into the development process:
Next, let us review some tips on how to address test failures in a CI pipeline.
• Interactions between the test framework and the CI system are not well dened
• e test suite running on the pipeline is too big
• Insucient test reporting
• Lack of collaboration between quality engineers, soware engineers, and infrastructure teams
Quality engineers should examine the pipeline frequently and always have a backlog of improvement
items lined up. Optimizations to the CI pipeline from a test automation perspective can be made by
consistent refactoring of tests to reduce akiness. Long-running tests should be set up for parallel
208 CI/CD and Test Automation
execution wherever possible. ere can be instances where the same tests are being run at the same
time in multiple pipelines. Data setup and teardown steps for each test should be built into the test to
account for such cases. CI/CD systems store a lot of pipeline-related data that can be used to generate
reliable metrics such as production deployment frequency, test runtime, test failure rate, and so on.
ese metrics provide helpful insights to improve overall product delivery times.
So far in this chapter, we have looked at the core CI/CD concepts and theoretically understood how
test automation can be accommodated in our CI pipeline. In the next section, let us acquire hands-on
experience of implementing one such pipeline using GitHub Actions.
For illustration, we will be using code commits and merges, which are common events that occur
in every repository. In this example, we will be conguring our workow le to be triggered when
someone pushes code to our repository. When this push event occurs, all jobs within the workow
will be run. is is demonstrated by the YAML code snippet shown next. In this conguration le,
we use the on parameter to specify the trigger for the workow. When the push event occurs, it
will run all jobs within this workow. We have a single job here that comprises multiple steps and
actions. Under the steps, two actions will be run in this case. e rst action will check out the latest
version of our code from the main/master branch, and the next one will run the super-linter against
it. Linters are tools to evaluate that our code conforms to certain standards. e super-linter supports
multiple languages and automatically understands and checks any code in the specied repository.
e runs-on parameter is used to specify the runner. is is the container environment where
GitHub Actions CI/CD 209
GitHub will run this job. ere are additional options to host your own container; however, we will
be sticking to the default container oered by GitHub in this case:
on: [push]
jobs:
super-lint:
name: Packt CICD Lint Job
runs-on: ubuntu-latest
steps:
- name: Checkout Code
uses: actions/checkout@v3
On navigating back to the home page of the repository, we notice a yellow status icon now, as shown
in Figure 9.6. is signies that the workow is being run now and the code is being checked. is
status icon turns green or red based on whether the checks pass or fail. is is particularly helpful
when you are viewing a new repository and it aids to know that the repository is in a healthy state
with all the tests passing. e results of the workow can be viewed by clicking on the status icon or
visiting the Actions tab:
We can view the execution results of a specic job by following the link within the Actions tab. is
provides a neat breakdown of the steps executed within the job and how long each one took. You
could open each step to view the run logs. Figure 9.7 shows the view for a failed job and its individual
steps executed as part of the workow:
e Actions tab is where all the CI/CD information is shown within a GitHub repository. It shows a
history of all our workow jobs and their statuses, with options to look through each one further in
detail. We can have as many workows as we need within a single hub repository. For example, we
could have one workow that runs only Cypress tests and another to lint the entire code repository.
On xing the suggestions from the linter and pushing the code to the repository, the CI job should
automatically be triggered based on our setting in our workow le.
e following is a sample snippet to invoke Cypress tests for reference. Placing these contents in a
workow le at the root of the project under the recommended directory structure triggers Cypress
tests on every commit to the repository:
- name: Cypress.io
uses: cypress-io/[email protected]
env:
DEFAULT_BRANCH: main
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Summary
We commenced this chapter by understanding what a CI/CD system entails and the processes involved.
We then dived deep into CI and CD individually to achieve a better understanding. en, we took up
test automation strategy considerations with respect to CI/CD processes. In the last section, we did
a hands-on exercise to create a CI job using the GitHub Actions tool. In the next chapter, we will be
learning about the common issues and pitfalls when working with test automation.
Questions
1. What is CI/CD and why is it necessary?
2. How is a CI process triggered?
3. What does a CI server do?
4. What are the aspects involved in CD?
5. How oen should E2E tests be run in the CI pipeline?
6. What is GitHub Actions and what is it used for?
10
Common Issues and Pitfalls
Test automation, with all its benets, helps engineering teams save time, eort, and resources. It
takes highly collaborative and skilled engineers to get test automation working at a large scale. Even
high-performing teams tend to go through multiple iterations before settling on a stable framework.
Teams typically encounter a wide variety of issues when it comes to test automation, and each team’s
journey is unique. In this chapter, I have tried to compile a list of teachings to guide you through this
process and help minimize any hurdles in your test automation undertaking. e main topics we will
be covering in this chapter are the following:
• Pay special attention when automating the tests that do not need to be run frequently. Automate
rare cases only when absolutely necessary.
• Automation costs are initially high and we will only start seeing the ROI aer several rounds of
execution, so it is all-important to focus on stable business scenarios that can reap the benets
in the long run.
• Minimize automating tests at the UI layer due to the brittleness of the frontend. Load the base
of the test automation pyramid as much as possible.
• Do not automate the usability aspects of your application.
• Avoid automating big and complex scenarios in the early phases of an automation framework.
Automating a complex scenario in a single ow will impact test stability and eventually result
in higher maintenance costs if the framework is not mature enough to handle it.
• Brittle selectors are the biggest cause of akiness in the UI tests. Working with your team and
identifying a solid selector strategy saves a lot of time in the long run.
Test engineers should strive to only automate the required and right set of test cases and should push
back if anyone says otherwise.
Recurrent issues in test automation 215
Let us now look at how important the architecture of the underlying system is to test automation.
ere should be no dierentiation between tests and core application logic when it comes to code quality.
Test code must be treated the same way as any other code would be in each repository. Applying coding
principles such as DRY, SOLID, and so on to test code helps keep the standards up. Test engineers
are oen tasked with getting the team up and running quickly with an automation framework. Even
though this is important, immediate follow-up tasks should be created to make the framework more
extensible and maintainable. Eventually, most of the test framework maintenance work will end up
in the backlog of test engineers and they should think through the code quality at every step.
218 Common Issues and Pitfalls
Coupling and cohesion are principal facets of coding that should be paid special attention to when it
comes to test code. Coupling refers to how a particular class is associated with other classes and what
happens when a change must be made to a specic class. High coupling results in a lot of refactoring
due to strong relationships between classes. On the other hand, loose coupling promotes scalability
and maintainability in test automation frameworks.
Cohesion refers to how close the various components of a class are knit together. If the method
implementation within a class is spread out across multiple classes, it gets harder to refactor, resulting
in high code maintenance eorts. For example, let us say we have a class that contains all the methods
to assert various responses from a single API endpoint. It would be termed loose cohesion if you added
a utility within the same class to generate reports from these assertions. It might seem related at a high
level, but a reporting utility belongs in its own class, and it can be reused for other API endpoints as well.
Let us next review the impact of code duplication.
Code duplication
Code duplication happens in a lot of test frameworks, most oen to get the job done quickly rather
than taking time to design it the right way. is hurts the maintainability of automation frameworks
eventually. It is essential to refactor and optimize test code frequently. Figure 10.1 illustrates a simplied
case of code duplication where there are two classes to generate distinct kinds of reports. In this case,
methodC and methodD are the only dierences between the classes. e rest of the class body is
duplicated, forcing multiple tests to instantiate both these classes every time they need to generate
reports. is results in a maintenance nightmare when there is a change in the way reports are generated
or when these classes are combined.
It is important to remember the rule of three when it comes to code duplication. Whenever there is a
need to duplicate a chunk of code a third time, it needs to be abstracted into a separate method or class.
Let us now look at how lengthy and complex tests aect test maintainability.
Extending existing tests and making them more complex oen results in brittleness and fragility
in the test suite. Engineers tend to add to the existing tests as the project scope increases and more
features are being delivered. is may seem like a viable solution in the short term, but it results in
complicated code for the rest of the team to follow. We have a code snippet here that shows a long test
that navigates to four dierent screens and validates multiple elds in the process. is can be easily
broken down into single tests in their own blocks or spec les if necessary:
Long and complex tests eventually result in adding timeouts in multiple places to account for slowness.
is results in increased akiness and long-running test suites. erefore, it is important to break down
the test code to follow the single responsibility principle as much as possible. It is hard to achieve this,
especially in end-to-end tests, where there is usually a business ow involved, but constant eorts
must be made to keep it as close to a single responsibility as possible.
Let us next review the ways to employ assertions.
Assertions are our primary instruments for validating the application logic in a test. ey should be
used correctly, sparingly, and sensibly. One surprising area of concern is when assertions are not used at
all. Engineers tend to use conditionals or write to the console instead of employing assertions, and this
should be avoided at all costs. Another pain point is when there are multiple assertions within a single
function or a test. is negates the primary logic of the test , thereby leading to undesirable results. A
third way in which assertions can be misused is when the right type of assertions are not employed.
e following code snippet illustrates a case where no assertions are being used. is is strongly
discouraged in a test:
function compute_product() {
...Test logic...
if (product==10){
console.log(product is 10);
else if (product==20){
console.log(product is 20);
}
else {
console.log(product is unknown);
}
return product;
}
Test automation anti-patterns 221
e next code snippet illustrates the use of multiple assertions in a single test. Use them sparingly
based on the test type and scenario:
cy.get([data-testid="user-name"]).should(have.length, 7)
cy.get([data-testid="bank_name"]).should(have.text, BOA
Bank)
cy.get([data-testid="form_checkbox"])
.should(be.enabled)
.and(not.be.disabled)
Lastly, the following code snippet shows the use of the same type of assertions for multiple UI elements.
Explore and employ the appropriate type of assertion based on the element being validated:
cy.get(#about).contains(About)
cy.get(.terms)contains(terms-conditions)
cy.get(#home).contains(Home)
Data can be mishandled easily – sometimes with dire consequences. ere are dierent types of
data that a test automation framework handles and stores. Each type of data has its place within
the framework and it should be handled as such. Mixing them up will result in an unorganized and
inextensible framework. Some of the common types are listed with examples:
• Functional test data: is drives the application logic and is seeded within the framework or
comes from a test environment.
• Dynamic test suite data: is is data required by the test scripts for execution, such as secrets:
• Global data: is is conguration data specic to particular environments, stored in config
les and the CI system:
DEV_URL= //test-development.com
STAGING_URL=https://test-staging.com
AWS_KEY=test-aws-key
222 Common Issues and Pitfalls
• Framework level constants: ese are constant values required by the tests and stored within
the framework in a non-extendable base class:
It is necessary to refactor test code according to changing requirements. Unfortunately, there are times
when additional requirements get added or existing requirements are modied beyond the scope
of an iteration. If the framework is not exible enough to accommodate refactoring, it is extremely
dicult to keep up with these changes. In an Agile world, it should be a top priority to make the test
automation framework extensible so that these changes can be made.
Let us review the use of UI tests to validate business logic next.
UI test automation should be restricted to testing high-level business ows, and all the business
rule validations should happen at the API level as much as possible. Many teams have wasted their
valuable resources by using UI automation to cover low-level business rules due to scripts breaking
at minor code changes. e initial overhead is way too high to realize any ROI with this approach. It
is extremely hard to acquire ne control over the system under test through UI components. ese
are also the slowest running tests in the test automation pyramid and hence deprive the teams of
valuable rapid feedback.
Let us now look at the eects of inecient code reviews.
Test automation anti-patterns 223
Code reviews, when not done correctly, lead to code that does not meet the quality standards of
an organization. Test automation code reviews are usually not performed at the same level as the
code delivered to customers. An inecient code review process may lead to a lack of code quality
standards and the introduction of new bugs into the existing framework. Chief items to look for in a
test automation code review are as follows:
at brings us to the end of our exploration of coding- and design-oriented anti-patterns. Let us now
explore a few process-oriented anti-patterns in test automation.
It is a widespread practice for soware engineers to assess the eort required to complete the work
of building a feature. In the Agile landscape, this is usually represented in story points. However, this
pattern unfortunately is broken quite oen for test automation, resulting in the accumulation of technical
debt. Every feature or story being worked on should be evaluated the same way for test automation
as it is done for manual testing and release. It is a common occurrence in the industry to punt the
test automation eorts to a later iteration due to tight deadlines and other technical limitations. is
can simply be avoided by considering test automation as an integral part of completing a feature. A
feature should not be considered complete unless the team feels they have sucient automated test
coverage for it.
224 Common Issues and Pitfalls
Table 10.1 shows a sample matrix that can be used to estimate test automation eorts in an Agile setup.
It can be customized to suit the team’s needs and skill sets:
Test engineers should be vocal about this aspect, as it takes time, eort, and commitment from the
whole team to get quality right. It is a process, and it evolves over time to yield fruitful results.
Let us understand the impact of starting automation eorts late next.
It is a frequent occurrence even in today’s Agile landscape that test automation doesn’t start until the
development of a feature is fully complete. Test engineers wait for the feature to be completed and
then begin planning for automation. is eventually demands a big push from the team to get tests
automated and, in turn, aects the quality of the output. It is true that there might be a few unknowns
in terms of the exact implementation details when the feature is being developed, but the ancillary tasks
required for test automation can be started and some may even be completed while the development is
in progress. Figure 10.2 illustrates how various test automation tasks can t into a development cycle.
Test automation anti-patterns 225
Oen, teams nd it really hard to compress all the test automation activities post-feature completion,
which results in project delays or, even worse, sub-par product quality by leaking defects into production.
Let us look at how proper tracking helps with test automation next.
I have witnessed a number of projects in which engineers have automated tests just because it is easy
to automate them. is ties back to our discussion in the previous section about selecting the right
tests but it deserves a special mention, as it could easily send the test automation suite into a downward
spiral. e most important consideration here is to add tests that are likely to catch bugs. Adding tests
just to increase the test coverage renders the suite inextensible and unmaintainable. It creates more
work for the future, where tests have to be trimmed down for various reasons.
is brings us to the end of our survey on process-oriented test automation anti-patterns. Let us
quickly summarize what we have learned in this chapter.
Summary
Our focus in this chapter was to understand the common issues and anti-patterns in test automation.
We started by looking at how unrealistic expectations aect test automation and also how not selecting
the right things to automate can impact test maintenance. We also reviewed the signicance of investing
in test environments and taking a whole-team and lean approach to test automation. We concluded
the section by understanding the need for planning around test data. Next, we reviewed a few coding-
and process-oriented anti-patterns in test automation. Some of the notable coding and design anti-
patterns are compromising the code quality in tests, code duplication, incorrect use of assertions,
and inecient code reviews. Subsequently, we reviewed process-oriented anti-patterns such as test
automation eorts not being assessed, test automation commencing late, and so on. is brings us to
the end of our joint exploration of test automation. We have come a long way from learning about the
basics of test automation to reviewing design anti-patterns in test automation frameworks. As you may
have noticed, test automation involves putting together several moving parts of a complex soware
application. e knowledge about tools and techniques acquired throughout this book should act as
a stepping stone for readers to explore test automation further.
Some potential next steps would be to dive deeper into each of the tools that we looked at and think
about how you can apply them in your current role and organization. e more hands-on experience
you gain with these tools and techniques, the more you will be ready to address new challenges in
test automation.
Happy exploring!
Questions 227
Questions
1. How can test engineers and SDETs manage unrealistic expectations of test automation?
2. What is the importance of test framework maintenance?
3. How do we select the right things to automate?
4. How does code duplication aect a test framework and how do we address it?
5. What are some of the correct ways to use assertions?
6. What are some items to look for in a test automation code review?
7. What are some tasks to keep track of in test automation?
Appendix A:
Mocking API Calls
API mocking is a process in which a mock server is congured to return the response of an API with
custom data. API mocking plays a principal role in test automation development. It unblocks testing
in situations where an external service might not be available or is too expensive to use for testing.
Mocking also helps in cases where one of the APIs is still under development and there is a need to
test a chain of API calls. A classic example where API mocking helps would be to unblock frontend
testing by mocking certain unavailable backend API calls. Some of the most common API mocking
tools and libraries include Jest, Postman, Cypress, JSON Server, and mocki.io.
In this appendix, we will be looking at the following:
e mock API server can be local or public and it helps temporarily remove the dependency between
the frontend and backend components. It is vital to remember that the API server responds purely
based on the incoming request and in no way provides a real picture of the data on the server side.
Having understood how API mocking works, let us quickly set up a mock API using Postman.
1. Create or use an existing Postman collection as seen earlier in Chapter 7, Test Automation for APIs.
2. Set up a request as shown in Figure A.2. ere are two scenarios where we end up mocking
an API request:
I. e rst is when we have a sample response from the API call, but subsequent requests
cannot be made to the API. We could save the response as an example in Postman and
use it for mocking.
II. e other one is when the API call does not exist or we do not have a sample. In this
case, we will have to build the response from the scratch. We will be simulating this
scenario in our example:
Mocking API calls using Postman 231
3. e next step is to create the mock server for our request as shown in Figure A.3. is can be
done by using the Mock Servers option on the le-hand pane and selecting the collection to
associate it with. Once this is done, a mock server URL is generated, to which a request can
be made. Postman also provides an option to make the mock server private by generating an
API key to authorize requests.
232 Appendix A:Mocking API Calls
4. e next step is to add an example to the request using the Options menu. We will be using
the dynamic variables in Postman to generate random values in our response. is can be a
static response as well. We will be using the following response in our example:
{ "age": {{$randomInt}},
"count": {{$randomInt}},
"name": "{{$randomLastName}}"
}
5. e nal step is to create a new request and use the mock server URL to make the API call.
Figure A.4 shows this in action.
Considerations for API mocking 233
By using a combination of environment and dynamic variables, it is possible to simulate almost any
kind of API response in Postman. Let us now look at a few important considerations when employing
mocks.
• A mock API server should mimic the real responses realistically. It should conform to the same
set of contracts as the real service.
• A mock API can be gured to simulate non-functional behavior such as slow response times,
various error responses, and so on.
• Mock APIs usually do not persist data like real APIs and the automation test frameworks should
account for their unique behaviors.
• Extra caution should be used when mocking external vendor APIs, as any uncommunicated
changes on the vendor side might break the mock and bring the testing to halt.
• e transition from a mock API to a real API should be planned in advance to ensure test
continuity.
234 Appendix A:Mocking API Calls
Summary
is appendix helped us understand the importance of mocks in testing and how to create one quickly
using Postman.
Assessments
is section contains answers to questions from all chapters.
3. e test pyramid acts as a guideline when planning for the test coverage of a soware product,
and it also helps to keep in mind the scope of each test so that it remains within the designed level.
4. Cloud-based tools enable geographically dispersed teams to scale test environments up/down
at will and also help in providing on-demand capacity for non-functional tests. Testing in the
cloud is one of the foundational pillars of DevOps processes.
5. Some common advantages of using design patterns in test automation are set out here:
8. e criteria to be considered when selecting a test automation tool include but are not limited
to the following:
e cost of the test automation tool and the ROI it oers over time
How well it ts with the team’s skillset
CI/CD Integration capabilities
Support for cross-device and cross-platform test setup and execution
Support for custom- scripting to extend the existing framework
Support for various technologies such as REST, SOAP, messaging systems (Kaa), and
databases
4. beforeEach blocks are used within a Cypress spec to enclose code that needs to run before
every it block.
5. e id attribute is selected using the # symbol.
6. cy.intercept() is the command to intercept and mock API calls in Cypress.
Ability to scale
Test and debug issues faster
Save resources in setting up an in-house mobile testing lab
5. Hooks are reusable code that can be run multiple times but dened only once. Hooks help
reduce test dependency, which in turn helps reduce code duplication.
6. Docker is a platform that assists in building, deploying, and testing your application code
on units called containers, irrespective of the underlying operating system. It provides great
portability for developing and testing applications.
7. GraphQL is a query language specication for APIs and helps design APIs in a client-driven
architecture. It excels at getting all the data needed by the client in a single request.
5. E2E tests should be congured to run on the pipeline for every deployment to a new environment.
6. GitHub Actions is a CI/CD platform that enables the automation of building, testing, and
deployment of application code. It is the built-in CI/CD tool for GitHub.
6. Some important aspects to look for when reviewing test automation code are:
7. Some critical items to keep a track of when it comes to test automation are:
L
latency
O
versus sample time 184 object-oriented programming (OOP) 104
listener 182
load testing 18
local variables 164
P
loops 94 Page Object Model (POM) 38-40
working with 95, 96 penetration testing 18
performance testing tool
requirements 66
selecting 66
248 Index
X
Xcode 142
Xcode Command Line Tools 142
XCUITest 126, 142
Packt.com
Subscribe to our online digital library for full access to over 7,000 books and videos, as well as
industry leading tools to help you plan your personal development and advance your career. For more
information, please visit our website.
Why subscribe?
• Spend less time learning and more time coding with practical eBooks and Videos from over
4,000 industry professionals
• Improve your learning with Skill Plans built especially for you
• Get a free eBook or video every month
• Fully searchable for easy access to vital information
• Copy and paste, print, and bookmark content
Did you know that Packt oers eBook versions of every book published, with PDF and ePub les
available? You can upgrade to the eBook version at packt.com and as a print book customer, you
are entitled to a discount on the eBook copy. Get in touch with us at customercare@packtpub.
com for more details.
At www.packt.com, you can also read a collection of free technical articles, sign up for a range of
free newsletters, and receive exclusive discounts and oers on Packt books and eBooks.
Other Books You May Enjoy
If you enjoyed this book, you may be interested in these other books by Packt:
https://packt.link/free-ebook/9781804615492