Exploratory Testing
Exploratory Testing
Maaret Pyhäjärvi
This book is for sale at http://leanpub.com/exploratorytesting
This is a Leanpub book. Leanpub empowers authors and publishers with the Lean Publishing
process. Lean Publishing is the act of publishing an in-progress ebook using lightweight tools and
many iterations to get reader feedback, pivot until you have the right book and build traction once
you do.
Dedication . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Place of exploration . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
An example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
Separate Tester Role . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
Future is Here, Just Not Evenly Distributed . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
Opportunity Cost . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
Heuristics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
Size of heuristics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
Purpose of heuristics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
The following chapters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
Process . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
In Autumn 2020, I intend to work through various chapters, and you will see major changes.
First, I’m bringing in materials from other sources and categorizing them.
Then, I combine and fill gaps.
If some aspect that I am writing on is more important to you, reaching out with a question is the
best way to target my energies around that particular topic.
I have been doing exploratory testing for 25 years. For me, it engulfs test automation. Test automation
is one of my ways of documenting, but it is also a way of doing things I shouldn’t do without code,
like staying up testing 24/7 or adding 1000 users. I recognize I’ve become better at it, even good,
through noticing that the gap analysis exploratory testing targeting information people who came
before me missed finds problems when I perform it, and finds somewhat less after I have been
around.
If you have ideas of how we can work together for me to teach this better, my DMs are open on
twitter where I am @maaretp.
About the Author
Every piece of writing will focus on the perspectives its author finds relevant. This chapter exists to
help you understand some of the experiences I consider core to myself.
My work
I work as a principal test engineer at Vaisala. Vaisala is an awesome product company working with
measurement technology. This book is not about my work at any of the companies I have work
with. As a matter of fact, I started writing this book with a rule that has served me well: ask for
forgiveness, not a permission. There are things that I would not have done that are valuable both
to me personally but my employers at those times that could have been blocked with waiting for
permission.
As a principal test engineer, my work is about testing. Or anything else I find I can do, want to learn
and that has value for us creating awesome products. I focus in particular in exploratory testing that
for me engulfs deep understanding of how programmers write their code (to understand risks they
are introducing both short-term and long-term) and many kinds of test automation (including one
focusing on regression testing). It’s not just about what I do, it’s about what we do, together.
I’m an expert explorer. I’m also a catalyst - things happen when I’m around. I believe that is the
power of information testing provides.
My Side Business
My employers have been supportive of my aspirations of keeping options open for years, and I have a
contract that allows me to work for other companies with a limited availability. On the side, I teach
commercial courses on testing: Exploratory Testing Academy, Exploratory Testing Work Course,
Test Case Design Course and Ensemble Testing Course are ones I’ve focused on recently. I have
favored tailoring my courses towards hands-on with the company’s own software.
My history
I started testing with localization testing for Microsoft. Moving from clicking through ready test
cases to a product company requiring me to figure out the tests I would run myself, I found my
calling in testing. I realized I did not only want to test but also work to make testing more respected.
About the Author 6
I’ve been a tester, a test manager, filled in for product owners, project managers and product owners,
and worked as a researcher in testing. I came back from the management track as I realized with
agile that self-organized teams enable me to be a superb tester. I decided to value great results and
my hands-on participation over perceived career progression.
I’ve had a job where I was “too valuable to test”. I believe that is a big misconception.
Conference Speaking
I speak a lot in conferences on topics of testing to connect with people I could learn with. Conference
speaking helps me find individuals to work things out with. It usually encourages the others to take
the first step to talk to me about stuff I already spoke on, and helps me bridge my insecurities in
speaking to random people about things they may not be interested on.
A lot means on average 30 sessions a year for the last few years. I’m working on cutting down.
Idealist
I believe in the scout rule: Things should be left in better shape than they were when I came in.
This drives me to figure out ways to leave organizations in better shape when I go find new
challenges (which I have done about every 3 years) and to make sure whatever I’ve learned I will
share.
About the Author 7
It also drives me to find ways of improving our software creation community - makers and menders,
smart creatives, all of us. There’s few projects in particular that come from this:
• European Testing Conference has been my platform for awesome testing contents on testing as
both testers and programmers know it, but also on fairer treatment of speakers in the conference
circuit.
• TechVoices is a thing to allow room for new voices in testing, an effort to help new speakers
through mentoring, and I’m a serial volunteer with Them
I’m a spokesperson for diversity, believing the lack of diversity we see in conferences does not
represent the talent around but the organizer’s contacts. In addition to diversifying speakers to
include women and people of color, a special focus of diversity I take is bringing out the voices
in Europe.
One of my forms of idealism is kindness in disagreement. I’m for dialog that seeks to understand
where the other is coming from, and have mild allergies to debate that seeks any ways of
communication to win over arguments. Safety is a prerequisite of learning and I take learning
seriously.
From Finland
I’m a Finnish woman living in Finland. Finns take pride in our education system and for me
personally it has enable me to be the first in my line of family to go to a university. Some say
that the most extroverted of us Finns are still introverts by any other standards.
My culture is built-in and it won’t leave me easily. Finland is amazing place to create software in
and as a small country, I feel we have a little lower walls between different beliefs in testing. We
have needed to agree to disagree while getting along.
And the weather sucks. I don’t want to talk about the weather. So I talk testing and anything software
development.
What and Where of Exploratory
Testing
This is a start of a section of writings that try many different approaches to explaining what is
exploratory testing and where in testing you find it. This is less of a discussion of definition, and
more of providing an opportunity to hook into something as multifaceted from one of the provided
angles. Each angle itself may teach you how to do some of it better, help you frame the work you
do.
What is Exploratory Testing?
It has been 34 years since Cem Kaner coined the term to describe a style of skilled multidisciplinary
testing common in Silicon Valley. I’ve walked the path of exploratory testing for 25 years and it has
been a foundational practice in becoming the testing professional I am today. Let’s look at what it
is, to understand why it still matters—more than ever.
An Approach to Testing
Exploratory Testing is an approach to testing that centers the person doing testing by emphasizing
intertwined test design and execution with continuous learning where next test is influenced by
lessons on previous tests. As an approach, it gives a frame on how we do testing in a skilled way.
We use and grow multidisciplinary knowledge for fuller picture of empirical information testing
can provide. With the product as our external imagination, we are grounded on what is there but
inspired to seek beyond it.
We learn with every test about the application under test, ourselves as the tool doing the testing,
other tools helpful in extending our capabilities and the helpful ways we can view the world the
application lives in. We keep track of testing that has been done, needs doing and how this all
integrates with the rest of the people working on similar or interconnected themes.
What makes our activity exploratory testing over other exploratory approaches founded in curiosity
is the intent to evaluate. We evaluate, seek for information we are missing, making sure what we
know is real with empirical evidence.
Specifying It By Contrast
It’s not a surprise that some folks would like to call exploratory testing just testing. In many ways it
is the only way of testing that makes sense—incorporating active learning is central to our success
with software these days.
To contrast exploratory testing with what people often refer to as manual testing, exploratory testing
as a skilled approach encompasses use of programming for testing purposes. We use our brains,
our hands as well as programs to dig in deep while testing. Sometimes the way of including test
automation happens through means of collaboration, where ideas from exploratory testing drive
implementation of automation that makes sense.
To contrast exploratory testing with people refer to as scripted testing, exploratory testing isn’t
driven by scripts. If we create scripts from exploratory testing, we know to use them in exploratory
What is Exploratory Testing? 10
fashion remembering that active thinking should always be present even when the script supports
us in remembering a basic flow. We’ve talked a lot about scripted testing as an approach where we
separate design—deciding what to test, and execution—making the test happen, and thus lowering
our chances of active learning targeting the most recent understanding of the risk profile.
Another contrast to programming centric views to testing comes with embracing the multidisci-
plinary view of of testing where asking questions like “is my application breaking the law today
after recent changes?” is something routinely encoded into exploratory testing, but often out of
scope for a group of automators.
Listen to Language
If you hear: “My boss asked me to test search so I searched something that was found and something
that wasn’t and reported I was done” you may be witnessing very low quality exploratory testing. It
relies on following high-level orders to an extent the tester can imagine based on their knowledge.
If you hear: “My colleague wrote me 50 cases of what to try out with search and I tried them
and reported I was done” you may be witnessing testing that isn’t exploratory. There is no hint
of learning, and owning responsibility of quality of the testing that happens.
What is Exploratory Testing? 11
If you hear: “My boss asked me to test search so I came back with 50 quick ideas of what could
be relevant and we figured out I’d just do 10 of them before we decided if going further was
worthwhile“, you are likely to be witnessing exploratory testing.
Similarly, in the automation first space, if you hear: “I got a Jira ticket saying I should automate this.
I did, and found some problems while at it, and extended existing automation because of the stuff I
learned.”, you may be seeing someone who is exploratory testing.
If you hear: “The Jira ticket said to automate A, B, and C, and I automated A and B, C could not be
automated.”, you may be witnessing testing that isn’t exploratory.
Look at who is in the center: is the tester doing the work and learning actively applying a better way
of doing the overall testing? If yes, that is exploratory testing.
As skilled approach, it is only as good as the skill of the person applying it. With focus on learning
through, skill may be a problem of today, but improved upon every day as exploratory testing is being
done. If you find yourself not learning, you most likely are not exploring. With the product as your
external imagination, you should find yourself imagining new routes through the functionalities,
new users with new perspectives, and relevant information your project teams would be happy to
make justified decisions on their take for the risk. With and without automation, in a good balance.
What is Exploratory Testing - the
Programmer Edition
In the new software world regime where programmers find themselves taking a lot more respon-
sibility of testing, we need to understand what exploratory testing is as it extends what most
programmer’s find their tests covering, and causes us talk past each other in understanding what
testing.
• Specification
• Feedback
• Regression
• Granularity
Specification means that tests you write can be concrete examples of what the program you’re about
to write is supposed to do. No more fancy words around high level concepts—give me an example
and what is supposed to happen with it. And when moving on, you have the specification of what
was agreed. This is what we made the software do, change is fine but this was the specification you
were aware of at time of implementation.
Feedback means that as the tests are around and we run the tests—they are automated, of course—
the tests give us feedback of what is working and what not. The feedback, especially when we
work with modern agile technical practices like test-driven development, gives us a concrete goal of
what we need to make work and if it is working. They help us anchor our intent so that given the
interruptions, we still can stay on the right path. And we can figure out if the path was wrong. This
is the test that passes, yet you say it isn’t right. What are we not seeing?
Regression means that tests don’t only help us when we’re building something for the first time,
but they also help us in changes. And software that does not change is dead, because users using
What is Exploratory Testing - the Programmer Edition 13
and loving it will come back with loads of new ideas and requirements. We want to make sure that
when we change something, we make only changes we intended. And regression is the perspective
of doing more than we intended, without tests without us knowing.
Granularity comes to play when our test fail for a reason. Granularity is about knowing exactly
what is wrong and not having to spend a lot of time figuring it out. We know that small tests pinpoint
problems better. We know that automation pinpoints problems better than people. And we know
that we can ask people to be very precise on their feedback when they complain something doesn’t
work. Not having to waste time on figuring out what is wrong is valuable.
This is not exploratory testing. Exploratory testing often guides this type of testing, but this is testing
as artifact creation. Exploratory testing focuses on testing as performance—like improvisational
theatre—in a multidisciplinary way beyond computer science.
• Guidance
• Understanding
• Models
• Serendipity
What is Exploratory Testing - the Programmer Edition 14
Guidance is not just about the specification, but general directions of what is better and what is
not. Some of it you don’t know to place in yes/no boxes, but have to clarify with your stakeholders
to turn them into something that can be a specification.
Understanding means that we know more about the place of our application in the overall world
of things, why people would find it valuable, how other’s design decisions can cause us trouble and
how what should be true if things were right always are not. It helps us put the details we’re asked
to code into a bigger picture—one that is sociotechnical and extending beyond our own organization
and powers.
Models are ways of encoding knowledge, so that we can make informed decisions, understand
things deeper and learn faster next time or with next people joining our teams.
Serendipity is the lucky accidents, running into information you did not expect to find. The lucky
accidents of new information about how things could and do go wrong when using your application
emerge given enough time and variety to use of your application. And knowing helps you not get
the escalations waking you up to critical maintenance tasks because who else would fix all of this
than the programmers?
An Approach To Testing
Exploratory testing is a approach to testing. It says whoever tests needs to be learning. Learning
needs to change what you are doing. You can’t separate designing of tests and executing them
without losing learning that influences your next tests. It is an approach that frames how we do
testing in a skilled way.
We don’t do just what is asked, but we carefully consider perspectives we may miss.
We don’t look at just what we are building, but the dependencies too, intentional and accidental.
Unsurprisingly, great programmer teams are doing exploratory testing too. Creating great automa-
tion relies on exploratory testing to figure out all the things you want to go check. While with
exploratory testing we believe that premature writing of instructions hinders intellectual processes,
we also know that writing that stuff as code that can be changed as our understanding grows, this
frees our mental capacity to think of other things. The executable test artifacts give us that peace of
mind.
Programmer teams are also doing what I would consider low quality exploratory testing with
limited ideas of what might make a difference in new information being revealed. And that is where
testers often come in—mindspace free of some of the programmer burdens, they focus their energies
elsewhere, raising the overall quality of work coming out of teams.
Finally, I want to leave you with this idea—bad testing is still testing. It just does not give much
of any of the benefits you could get with any testing. Exploratory testing and learning actively
transforms bad testing to better.
Where is Exploratory Testing
When people start learning about testing, and agile testing in particular, they quickly get to a model
of testing quadrants. Testing quadrants, popularized by Janet Gregory and Lisa Crispin with their
Agile Testing book, place a collection of testing words in four quadrants. When you go look, you can
find “exploratory testing” in the top right corner, meaning it is considered Business Facing Product
Critique.
As the term was coined 35 years ago to express a specific approach to testing, making it a technique
in one corner of the quadrants was not the intent. It expressed a style of testing unfamiliar to the
majority, that was observable in Silicon Valley product companies, a skilled multidisciplinary testing
under product development constraints.
The world moved on, and testing certifications had hard time placing a whole approach of testing
into their views of the world. With introduction of ways to manage this style of testing (session-
and thread-based exploratory testing), those seeking to place it in the technique box combined the
management style and defined their idea of using only limited time - separately defined sessions -
on this way of testing and everything it was born to be different from remained in the center.
That means that in the modern world, exploratory testing is two things:
As a technique, you can put it in the corner of quadrants. As a technique, you can put it on top of
your test automation pyramid and make jokes about the pyramid turning into an ice cream cone
with too much of exploratory testing on top. But as an approach, it exist for every quadrant, and for
every layer.
Due to the great confusion, questions about the other testing I do on top of exploratory testing are
quite common.
Surely Exploratory Testing is not the only testing you are doing. I see it as a “plus” on top
of feature testing, regression, all the non-functional testing. Exploratory fills the gaps.
But for me, it does not fill the gaps. It is the frame in which all other testing exists. It is what
encourages short loops to learn, challenges the limits of what I already have learned, makes me pay
attention to what is real, and creates a sharp focus on opportunity cost.
I scribbled an image on paper, that I recreated for purposes of this blog post. If all these shapes
here are the other kinds of testing mentioned: feature testing, regression testing and non-functional
testing, what is the shape of exploratory testing?
The shape of exploratory testing is that it fills the gaps. But it also defines the shape of all the other
tests. It’s borders are by design fuzzy. We are both right: for me it is the frame from which all the
other testing exists, even when it fills gaps.
There is such thing as non-exploratory testing. It’s the one where shape of other tests stay in place
and are not actively challenged, and where particular artifacts are important over considering their
value and opportunity cost.
Where I worked, we had two teams doing great at testing. Both teams explored and left behind
test automation as documentation. When asked what percentage they automated, their responses
were very different. One automated 100%, and it was possible by not having as many ideas of what
Where is Exploratory Testing 17
testing could be. The other automated 10%. Yet they had just as much automation as the first, but
often found problems outside the automation box. Easiest way to get get to 100% is by limiting your
ideas of what testing could be.
Seeing there’s plenty of space in between the shapes and plenty of work in defining the shapes can
be a make or break for great testing.
Place of exploration
Over the years, I’ve worked with places where release cycles grow shorter. From integrating all
changes into builds a couple of times a week, we’ve moved over to continuous integration. Each
change gets integrated to the latest system and made available for testing as soon as the build
automation finishes running. We don’t get to test the exactly same thing for a very long time, or if
we do, we spend time on something that will not be the final assembly delivered. Similarly, we’ve
moved from giving those assemblies to customers once every six months to continuous delivery and
the version in production can change multiple times a day.
In the fast-paced delivery world, we turn to look heavily at automation. As we need to be able to
run our tests again and again, and deliver the change as soon as it has been checked in and run
through our automated build and test pipeline, surely there is no place for exploratory testing? Or if
there is, maybe we just do all of our exploratory testing against a production version? Or maybe on
top of all this automation, exploratory testing is a separate activity, happening just before accepting
the change into the assembly that gets built and pushed forward? Like a time-box spent on testing
whatever risks we saw the change potentially introducing that our automation may not catch?
Think of exploratory testing as a mindset that frames all testing activities - including automation.
It’s the mindset that suggests that even when we automate, we need to think. That the automation
we are creating for continuous testing is a tool, and will be only as good as the thinking that created
it. Just like the application it tests.
An example
We were working in a small team, building the basis for a feature: managing Windows Firewall
remotely. There were four of us: Alice and Bob were the programmers assigned at the task. Cecile
specialized in end to end test automation. David could read code, but on most days chose not to and
through of themselves as the team’s exploratory testing specialist.
As the team was taking in the new feature, there was a whole group discussion. The group talked
about existing APIs to use for the task at hand, and figured out that the feature had a core. There
was the existing Windows Firewall. There was information about rules to add delivered. And those
rules needed to be applied, or there would not be the feature. After drawing some boxes on the wall,
having discussions about overall and minimal scope, the programmers started their work of writing
the application code.
It did not take long until Alice checked in the module frame, and Bob reviewed the pull request
accepting the changes making something available that was still just a frame. Alice and Bob paired
to build up the basic functionality, leading Cecile and David listening to them bouncing off ideas of
Place of exploration 19
what was the right thing to do. As they introduced functionality, they also included unit tests. And as
they figured out the next slice of functionality to add, David was noticing how much of exploratory
testing the two did between the pair. The unit tests would surprise them on a regular basis, and they
took each surprise as an invitation to explore in the context of code. Soon the functionality of adding
rules was forming, and the pull requests were accepted within the pair.
Meanwhile, Cecile was setting up possibilities to run the Windows Firewall in a multitude of
Windows operating systems. They created a script that introduced five different flavors of Windows
that were supposed to be supported for the new functionality to be run as jobs within the continuous
integration pipeline. They created libraries that allowed to drive the Windows Firewall in those
operating systems, so that one could programmatically see what rules were introduced and shown.
Since the team had agreed on the mechanism of how the rules would be delivered from the outside,
they also created mechanisms of locally creating rules through the same mechanism.
As soon as the module could be run, Alice and Bob would help out Cecile on getting the test
automation scripts running on the module. David also participated as they created the simplest
possible thing that should work: adding a rule called “1” that blocked ping and could be verified in
system context by running ping before and after. Setting up the scripts on top of Cecile’s foundation
was straightforward.
Cecile wanted to test their scripts before leaving them running triggered for an hourly repeat for a
baseline, and manually started the run on one of their operating systems, visually verifying what
was going on. They soon realized that there was a problem they had not anticipated, leaving the
list of rules in an unstable state. Visually, things were flickering when the list of rules was looked
at through the UI. That was not what happened when rules were added manually. And Cecile had
explored enough of the system to know what adding a rule through the existing user interfaces
should look like. Something was off.
Cecile, Bob and Alice figured out that the problem was related to naming the rules. If the rule name
was less than three characters, there was a problem. So Bob introduced a fix limiting rule’s minimum
length, Alice approved the change and Cecile changed the rules to have a name longer than three
characters. Cecile used Windows Firewall more to figure out different types of rules, and added
more cases by exploring what was same and different and made sure they would test things both
locally and remotely - end to end.
David had also started exploratory testing the application as soon as there were features available.
They had learned that Alice and Bob did not introduce logging right from the start, and as they
did, that the log wasn’t consistent with other existing logs in how it was named. They were aware
of things being built into the automation, and focused their search on things that would expand
the knowledge. They identified that there were other ways of introducing rules, or locking the
Windows Firewall so that rules could not be introduced through external mechanisms. They would
pay attention to rule wizard functionalities in the Windows Firewall, enforcing rules around legal
rules, and make notes of those only to realize through testing that Alice and Bob had not considered
that all combinations were not legal. Things David would find would not be bugs as the team defined
a bug - programming errors - but more of missing functionalities, for lacking information about the
execution environment.
Place of exploration 20
David would make lists of tests for Cecile to add to the test automation, and pair with Cecile to
add them. As they were pairing, the possibilities of automatically creating a lot of rules triggered
their minds and they would try introducing a thousand rules to note performance concerns. And as
adding was so much fun, obviously removing some of them would make sense too. They would also
add changing rules. And as they were playing with numbers, they realized that they had uncovered
a security issue: rules were there to protect, and timings would allow for times of unprotection.
The team built it all to a level they felt was minimal to be delivered outside the organization. Unit
tests and test automation allowed for making changes and believing those cases still worked out ok.
They could explore around every change, and every idea.
The functionality also included a bit of monitoring, allowing them to see the use of feature in
production. After having the feature running in production, monitoring provided extra ideas of
what to explore to understand the overall system better.
What this story shows: * everyone explores, not everyone calls it exploratory testing even if it is
that * we explore before be build, during building, while we automate and separately from building
and automating, as well as while in production * exploration can happen in context of code and in
context of the system we’re building as well as in context of use in the overall system * without
exploratory testing, we don’t give ourselves the best chances of knowing what we’re building
Learning
If we run a test but don’t stop to learn and let the results of the test we just run influence our choices
on the next test, we are not exploring. Learning is a core to exploring. Exploring enables discovery
of information that is surprising, and the surprise should lead into learning.
The learning attitude shows in the testing we do so that there is testing against the risk of regression,
but a lot of times the risk isn’t best addressed by running exact same tests again and again.
Understanding the change, seeking out various perspectives in which it might have impact and
introduce problems that were not there before is the primary way an exploratory tester thinks.
Whatever I test, I approach it with the idea of actively avoiding repeating the same test. There’s so
much I can vary, and learning about what I could vary is part of the charm of exploratory testing.
When we optimize for learning and providing as much relevant information as we can with whatever
we have learned by that time, we can be useful in different ways at different phases of our learning
with the system.
The Two Guiding Principles 23
Opportunity Cost
Whatever we choose to do is a choice away from something else. Opportunity cost is the idea of
becoming aware of your choices that have always more dimensions than the obvious.
There are some choices that remove others completely. Here’s a thought experiment to clarify what
I mean: Imagine you’re married and having hard time with your spouse. You’re not exactly happy.
You come up with ideas of what could be changed. Two main ideas are on the table. One is to go
to counceling and the other is to try an open relationship. If you choose the latter and your spouse
feels strongly against this, the latter option may no longer be available. The system has changed.
There are some choices that you can do in different order and they still are both relevant options.
If you choose to test first with a specification, you will never again be the person who has never
read the specification. If you choose to test first without the specification, you will never have the
experience of what you would notice if your first experience was with a specification.
There are some choices that leave others outside scope. If you choose to use all your time in creating
automation and avoiding following the exploration ideas you generate while automating as basic
cases already require effort, you leave the information exploring could provide out of scope. If you
choose to explore and not automate, you leave repetitive work of future to be done manually or
undone.
The idea of being aware of opportunity cost emphasizes a variety of choices where there is no one
obviously correct choice in the stream of small decisions. We seek to provide information, and we
can do so with various orders of tasks.
It’s good to remember that rarely we have an endless schedule and budget. So being aware of
opportunity cost keeps us focused on doing the best testing possible with the time we have available.
How to Explore with Intent -
Exploratory Testing Self-Management
This article was published in Ministry of Testing Testing Planet in 2016. Appropriate pieces of it will
find their place as part of this book.
Exploratory testing is the wonderful idea that we can use our freedom of choice while testing, to
learn as we go on and let that learning influence the choices we make next. The system we test
is our external imagination, and it’s our responsibility to give it the chance to whisper out all the
information there is.
When we test, everyone is allowed to stretch their assigned boxes with exploration at least a little.
Even the most test case oriented organizations will ask you to think, learn, and look around while
executing your assigned tests. That’s what makes you good at testing in the organization.
For more of a stretch, these organizations will allow for a few hours of freedom from the assigned
box, to do some time-boxed exploratory testing for finding gaps your usual test case harness keeps
you from spotting.
Others, like myself, work in the exploratory testing mode full time. In this mode, test cases (if such
will exist) are an output of the process instead of an input and created at a time we know the most
about a feature or product. We’ve learned a lot by the time we’re done testing.
Regardless of whether your mode of exploratory testing is using it as technique (extending your
test cases), as a task (time-boxing exploration) or as an approach (engulfing all your thinking of
testing), there’s a critical skill of self-management you’ll need to develop. You’ll want to explore
with intent, keep track of what you know and learn, and what more there is to learn. All of this will
grow iteratively and incrementally as you do this type of testing.
started. You would do well acknowledging where your abilities are and developing them further by
practicing intertwining, but also allowing yourself time to focus on just one thing. With exploratory
testing, the formula includes you: what works for you, as you are today.
A Practical Example
Imagine learning to drive a car. You’re taking your first lessons at the driving school and after some
bits of theory you know the basic mechanics of driving but have never done any of it.
You’ve been shown the three pedals, and when you stop to think, you know which one is which.
You know the gear shifter and it’s clear without telling what the steering wheel does (as long as you
drive forward, that is). And finally comes the moment you’re actually going to drive.
The driving instructor makes you drive a couple of laps around the parking lot and then tells you
to drive out, amongst other cars. With newness of all of this, your mind blanks and you remember
nothing of the following half an hour. And if you remember something, it’s the time when your car
stopped at an embarrassing location because it was too hard to do the right combination of clutch
and gears.
All the pieces are new and doing the right combination of even two of them at the same time is
an effort. Think about it, when you looked if you could turn right, didn’t you already start turning
the wheel? And when you were stopped at the lights to turn, didn’t it take significant effort to get
moving and turn at the same time?
After years of driving, you’re able to do the details without thinking much, and you’re free to use
your energy on optimizing your route of the day or the discussion you’re having with the person
next to you. Or choosing a new scenic route without messing up your driving flow.
It’s the same with testing. There’s a number of things to pay attention to. The details of the
application you’re operating. The details of the tools you need to use. The uncertainties of
information. All your thoughts and knowledge. The information you get from others, and whether
you trust it or not. The ideas of what to test and how to test it. The ideas of what would help you test
again later. The expectations driving you to care about particular type of information. Combining
any two of these at a time seems like a stretch and yet with exploratory testing, you’re expected to
keep track of all of these in some way. And most essentially from all the details, you’re expected to
build out and communicate both a long-term and a short-term view of the testing you’ve done and
are about to do.
Learning To Self-manage
I find that a critical skill for an exploratory tester is the skill to self-manage, and to create a structure
that helps you keep track of what you’re doing. Nowadays, with some years of experience behind
me, I just create mind maps. There is a simple tool I found to be brilliant for learning the right kind
of thinking, and that tool is what I want to share with you.
How to Explore with Intent - Exploratory Testing Self-Management 26
When I say tool, I mean more of a thinking tool. The thinking tool here though has a physical
structure.
For a relevant timeframe, I was going around testing with a notebook for a very particular purpose.
Each page in the notebook represented a day of testing, and provided me a mechanism to keep track
of my days. A page was split into four sections, with invisible titles I’ve illustrated in the picture:
Mission (why am I here?), Charter (what I’m doing today?), Details (what am I keeping track of in
details?) and Other Charters (what should I be doing before I’m done?).
At the start of a day of testing, I would open a fresh page and review my status after letting earlier
learning sink in. Each of the pages would stay there to remind me of how my learning journey
developed as the application was built up, one day at a time.
Notebook illustration
Mission
In the top left corner, I would stick a note about my mission, my purpose or as I often liked to think
of it, the sandbox I was hired to play in. What did the organization expect of me as per information
I would provide, having hired me as an exploratory tester? How I could describe that in just a few
sentences?
How to Explore with Intent - Exploratory Testing Self-Management 27
For example, I was hired in an organization with ten teams, each working on a particular area of the
product. My team was specializing in installations. That little note reminded me that while I could
test anything outside the installations if I so wished, there was a sandbox that I was supposed to
cover for relevant findings and it was unlikely that others would feel the urge to dig deep into my
area.
They were likely to travel through it, but all the special things in the area, they would probably
rather avoid. If I would be digging through someone else’s area, nothing would stop me. But I might
leave mine unattended. I might feel that I used all this time, and therefore I’m done, even if I was
only shallowly covering my own area.
The mission note reminded me of the types of information the organization considered relevant,
and the area of responsibility I felt I had accepted. It served as an anchor when the whispers of the
product lead me elsewhere to explore.
Charter
In the top right corner was my note about the work of the day: the Charter. Each morning I would
imagine what I was trying to achieve today - only to learn most evenings I had done something
completely different. Charter is a framing of what I’m testing, and as I learn they change over time.
It’s acceptable to start out with one idea and end up with something completely different when you
are finished.
The note of the day was another anchor keeping me honest. With exploration, I’m not required to
stick to my own plans. But I’m required to be in control of my plans in the sense that I don’t fool
myself into believing something is done just because the time is used.
Continuing on my example with the Installations team, I might set up my charter of the day to
be 2 installations with a deep dive into what actually gets installed. Or I might set it up to be 20
installations, looking through each shallowly. Or I might decide to focus on a few particular features
and their combinations. If I saw something while testing that triggered another thought, I could
follow it. But at the end of the day, I could review my idea from the morning: did I do 20 shallow
installations like I thought I would? If I didn’t, what did I do? What am I learning for myself from
how things turned out?
Details
In the bottom right corner, I would pile up notes. At first, these were just lines of text I would write
that would often fill the page next to the one I was working on. Later, I realized, that for me there
were three things I wanted to make notes of: the bugs, the questions, the ideas for test automation
or test cases, and my notes extended to have a categorization shorthand.
With any of the detailed ideas, I could choose to stop doing the testing I was doing, and attend to
the detail right away. I could decide that instead of focusing on exploring to find new information,
I could create an automated test case from a scenario I cooked up from exploration. I could decide
How to Explore with Intent - Exploratory Testing Self-Management 28
that instead of completing what I was planning on doing today, I would write the great bug report
with proper investigation behind it. I could decide to find a product owner, a support representative,
a programmer, or my manager to get an answer for a burning question I had. Or, I could make note
of any of these with minimum effort, and stick to my idea of what I would do to test the application
before attending to the details.
I learned that people like me can generate so many questions, that if I don’t have a personal throttling
mechanism, I can block others from focusing on other things. So I realized that collecting the
questions and asking them in regular intervals was a good discipline for me. And while looking
through my questions, I would notice that I had answers to more questions myself than I first
thought.
With each detail, the choice is mine. Shall I act on this detail immediately, or could it wait? Am I
losing something relevant if I don’t get my answer right away? Is the bug I found something the
developer would rather know now, than at the end of my working day? Do I want to stop being in
exploratory mode to improve my documentation, or to pair with a developer to implement a piece
of test automation, or do I rather time-box that work for another day from the idea I had while
testing?
Other Charters
In the bottom left corner, I would make notes of exploratory testing work I realized needed doing
while I was testing. I would write down ideas small and large that I would park for future reference,
sometimes realizing later that some of those I had already covered and just forgotten. Sometimes I
would add them to my backlog of work to do, and sometimes tuning the existing backlog of work
to support choosing focus points of upcoming testing days.
Some of my ideas would require creating code for purposes of extending the reach of exploration.
Some ideas would require getting intimately familiar with the details of log files and database
structures. Each new idea would build on the learning that had happened before, making me reassess
my strategy of what information I would invest in to have available first.
You’re In Control
The tool isn’t there to control you, it’s there to give you a structure to make your work visible for
you. You get to decide what happens when you explore, and in what order. If you need to go through
a particular flow 15 times from various angles, you do that. If you find it hard to think about strategy
and importance of particular tasks when you’re deep in doing testing, you reserve time separately
for strategic thinking.
With the days passing, and notes taken, I could go back seeing what types of sessions I would
typically have. There would be days where I’d just survey a functionality, to figure out a plan of
charters without focus on details. There would be target rich functionalities, where the only detail I
could pay attention to was the bugs. Over time, I could pay attention to doing things intentionally
How to Explore with Intent - Exploratory Testing Self-Management 29
with particular focus, and intentionally intertwined. I could stop to think, how different days and
different combinations made me feel. I learned to combine things in ways that were useful for my
organization, but also maximized the fun I could have while testing in a versatile manner.
While most value was in learning to self-manage my testing work around learning, there was also
a side impact. When someone would show up to ask about what I had done and was doing, I could
just flip a page and give an account of what had been going on. Seeing the structure created trust in
those who were interested in my progress.
As an active learner, you will get better every day you spend on testing. Exploratory testing treats
test design, test execution and learning as parallel, as mutually supportive activities to find unknown
unknowns. Doing things in parallel can be difficult, and testing needs to adjust to the tester’s
personal skill level and style. Your skill to self-manage your work and your learning - making
learning and reflection a habit - is what differentiates skilled exploratory testing from randomly
putting testing activities together.
I believe that the thing that makes us, testers, to not be treated as a commodity, is learning. It’s the
same with programmers. Learners outperform the ones that don’t. Exploratory testing has learning
at it’s core.
Yesterday in a testing workshop I run 3rd time in this format online, something interesting happened.
I noticed a pattern, and I am indebted to the women who made it so evident I could not escape the
insight.
We tested two pieces of software, to have an experience on testing that enabled us to discuss what
testing is, why it is important and if it interests us. On my part, the interest is evident, perhaps even
infectious. The 30 women new to creating software to the skills in that space.
The first software we tested was the infamous Park Calculator. The insight that I picked up on
came quite late to a bubbling discussion on how many problems and what kind of problems we
were seeing, when someone framed it as a question: Why would the calculator first ask the type
of parking and then give the cost of it, when a user would usually start with the idea that they
know when they are traveling, and would benefit from a summary of all types of parking for that
timeframe? The answer seems to be that both approaches would fit some way of thinking around
the requirements, and what we have was the way who ever implemented this decided to frame
that requirement. We found a bug, that would lead to a redesign of what we had, even if we could
reuse many of the components. Such feedback would be more welcome early on, but if not early,
discussing this to be aware was still a good option.
The second software we tested was the GildedRose. A piece of code, intertwined with lovely clear
requirements, often used as a way of showing how a programmer can get code under tests without
even reading the requirements. Reading the requirements leads us to a different, interesting path
though. One of the requirements states that quality of an item can never be negative and another
one tells it is maximum 50. Given a list of requirements where these two are somewhere in the
middle, the likelihood of a tester picking these up to test first is very high - a fascinating pattern in
itself. However, what we learn from those is that there is no error message on an input or output
beyond the boundaries as we expect, instead given inputs outside boundaries the software stays on
How to Explore with Intent - Exploratory Testing Self-Management 30
the level of wrongness of input not making it worse, and given inputs barely at boundaries it blocks
the outputs from changing to wrong. This fits the requirement, but goes as a confusing design choice.
The two examples together bring out a common pattern we see in testing: sometimes what we have
is what we intended to have, and fits our requirements. However, we can easily imagine a better
way of interpreting that requirement, and would start a discussion on this as a bug we know will
stretch some folks ideas of what a bug is.
Going beyond Defaults
With a new job, comes a new mobile phone. The brand new version of iPhone X is an upgrade to
my previous iPhone 7, except for color - the pretty rose gold I come to love is no longer with me.
The change experience is fluent, a few clicks and credentials, and all I need is time for stuff to sync
for the new phone.
As I start using the phone, I can’t help but noticing the differences. Wanting to kill an application
that is stuck, I struggle when there is no button to double click to get to all running applications. I
call out for my 11-year-old daughter to rescue and she teaches me the right kind of swipes.
Two weeks later, it feels as if there was never a change.
My patterns of phone use did not change as the model changed. If there’s more power (features) to
the new version, I most likely am not taking advantage of them, as I work on my defaults. Quality-
wise, I am happy as long as my defaults work. Only the features I use can make an impact on my
perception of quality.
When we approach a system with the intent of testing it, our own defaults are not sufficient. We
need a superset of everyone’s defaults. We call out to requirements to get someone else’s model of
all the things we are supposed to discover, but that is only a starting point.
For each claim made in requirements, different users can approach it with different expectations,
situations, and use scenarios. Some make mistakes, some do bad things intentionally (especially for
purposes of compromising security). There’s many ways it can be used right (“positive testing”) and
many ways it can be used wrong (“negative testing” - hopefully leading to positive testing of error
flows).
Exploratory testing says we approach this reality knowing we, the testers, have defaults. We actively
break out of our defaults to see things in scale of all users. We use requirements as the skeleton map,
and outline more details through learning as we test. We recognize some of our learnings would
greatly benefit us in repeating things, and leave behind our insights documented as test automation.
We know we weren’t hired to do all testing, but to get all testing done and we actively seek everyone’s
contributions.
We go beyond the defaults knowing there is always more out there.
Heuristics
When we would like to have a rule of how the world works, but we quite can’t make one because
everything depends, we still have ideas of what might be helpful rule-like constructs. Exploratory
Testing is full of them, and we like to call them heuristics.
We pass heuristics forward as the folklore, wisdom of the past of what has worked.
We use heuristics elaborately sometimes knowingly and sometimes unconsciously - they help as
shortcuts in situations where there are already too many things to think of.
As far as I am concerned, I have not yet discovered a great way to categorize heuristics. But I seem
to use two dimensions.
Size of heuristics
Some heuristics are models that help us do what we need to do in testing. Models tend to grow
bigger in size, and take a form of listing things to consider.
Things we notice we are doing in our projects are smaller in size and it can be really helpful to
label them. With these types of heuristics, I follow Alex Schladebeck’s convention and call them
microheuristics. Instead of creating a theory of everything, we can appreciate the smallest pieces of
wisdom we pass on.
Purpose of heuristics
I have come across multiple applications for heuristics, and for now I focus on two major ones.
• Recall heuristics help with test ideation. We need to come up with ideas to make choices, how
do we learn to do that?
• Decision heuristics help with explaining directions we are taking for test strategy, for testing
in the moment and for conversations we have about our testing.
If the only tool you know is a hammer, everything starts to look like a nail.
It’s not just that everything starts to look like a nail, we are only capable of noticing nails.
The most common nail of testers that I see is the error handling cases of any functionality. This
balances the idea that most common nail programmers see is the sunny day scenario of any
functionality, and with the two roles working together, we already have a little better coverage
over functionality in general.
To avoid the one ingredient recipe, we need awareness of all kinds of ingredients. We need to know
a wide selection of options for how to document our testing from writing instructional test cases, to
making freeform notes to making structural notes on individual level to making structural notes on
group level to documenting tests as automation as we are doing it. We need to know a selection of
coverage perspectives. We need to know that while we are creating programs in code, they are made
for people and a wide variety of people and societal disciplines from social sciences to economics
to legal apply. We need to know relevant ways things have failed before, being well versed in both
generally available bug folklore as well as local bug folklore, and to consider both not failing the
same way, but also not allowing our past failures to limit our future potential and drive testing by
risk, not fear.
This all comes down to the moment you sit in a team meeting, and you do backlog refinement over
the new functionality your team is about to work on. What are the tasks you ensure the list includes
so that testing gets done?
In that moment, what I find useful being put on the spot is recall heuristics. Something that helps
me remember and explain my thoughts in a team setting. We can’t make a decision in the moment,
without knowing our options.
I find I use three different levels of recall heuristics to explore what I need to recall my options in a
moment. Each level explores at a different level of abstraction:
Recall Heuristics for Test Ideation 34
change: starting from a baseline where the code worked, a lot of times what I get to test is on a level
of code commit to trunk (or about to head to trunk).
• story: starting from a supposingly vertical slice of a feature, a user story. In my experience
though people are really bad at story-based development in teams, and this abstraction is
available rarely even if it is often presented as the go-to level for agile teams.
• feature: starting from value collection in the hands of customers where we all can buy into the
idea of enabling new functionality.
For a story level recall heuristic, I really like what Anne-Marie Charrett has offered in her post here².
Simultaneously, I am in a position of not seeing much of story-based development but backlogs
around me tend to be on value items (features and capabilities) and the story format not considered
essential.
Sometimes this happens in a backlog refinement meeting, the whole team brainstorming how we
would test a feature.
Sometimes this happens in a pair, coming up with ideas of what we’d want to see tested.
Sometimes this happens alone, thinking through the work that needs doing for a new feature when
the work list is formed by process implying “testing” happens on every story ticket and epic ticket
level without agreeing what it specifically would mean.
• (L) Learning: Where can we get more information about this: documents, domain understand-
ing, customer contacts.
• (A) Architecture: What building it means for us, what changes and what new comes in, what
stays.
• (F) Functionality: What does it do and where’s the value? How do we see value in monitoring?
• (P) Parafunctional: Not just that it works, but how: usability, accessibility, security, reliability,
performance…
• (D) Data: What information gets saved temporarily, retained, and where. How do we create
what we need in terms of data?
• (E) Environment: What does it rely on? How we get to see it in growing pieces, and where?
• (S) Stakeholders: People we hold space for. Not just users/customers but also our support, our
documentation, our business management.
• (L) Lifecycle: Features connect to processes, in time. Not just once but many times.
• (I) Integrations: Other folks’ things we rely on.
Recalling helps make choices as we are aware of our choices. It helps call in help in making those
choices.
Automation First Microheuristic
Developers announce a new feature is available in the build and could use a second pair of eyes.
What is the first thing to do? Changing companies made me realize I have a heuristic on deciding
when I automate test cases as part of exploratory testing.
Both automating and not automating end up bringing in that second pair of eyes, that seeking of
understanding the feature and how it shows in the relevant flows. The first level of making the choice
if you start with automating is if you are capable of automating. It makes the choice available on an
individual level, and only after that it can be a choice.
When that choice is available, these things could impact choosing Automation First. * Belief that
change in the basic flow matters beyond anything else you imagine wrong with it
1 * When automating, you will visually and programmatically verify the basic flow as\
2 you are building it. Building it to a good reliable level takes longer than just lo\
3 oking at it but then remains around to see if changes in software change the status \
4 of it.
I was thinking of this as I realized that the automated tests on my current system see very few
problems. There is no relevant environmental difference, like with my previous job. Automation
works mostly in the change dimension, unlike my previous job.
Going into the moment of making this choice, I find I still go back to my one big heuristic that
guides it all: Never be bored. First or Second does not matter as much as the idea that keeping
things varied helps keep me away from boredom. Documenting with automation makes sense to
avoid that boredom in the long run.
How would you test a textfield?
I’ve been doing tester interviews recently. I don’t feel fully in control there as there’s an established
way of asking things that is more chatty than actionable, and my bias for action is increasing. I’m
not worried that we hired the wrong people, quite the opposite. But I am worried we did not hire
all the right people, and some people would shine better given a chance of doing instead of talking.
One of the questions we’ve been using where it is easy to make step from theory to practice is How
would you test a text field? I asked it in all, around a whiteboard when not on my private computer
with all sorts of practice exercises. And I realized that the exercise tells a lot more when done on a
practice exercise.
In the basic format, the question talks of how people think of testing and how they generate
ideas. The basic format as I’m categorizing things here is heavily based on years of thinking
and observation by two of my amazing colleagues at F-Secure Tuula Posti and Petri Kuikka, and
originally inspired by discussions on some of the online forums some decades ago.
quit quickly as if it was irrelevant question. They may mention a more varied set of ideas, and list
alphabetic, numeric, special characters, double-byte characters, filling up the field with long text,
making the field empty, copy-pasting to the field, trying to figure out the length of the field, erasing,
fitting text into the visible box vs. scrolling, and suggest code snippets of HTML or SQL, the go to
answer for security. They’ve learned there’s many things you can input, and not just basic input
into the field, but it also has dimensions.
This group of people often wants to show the depth of their existing experience by moving the
question away from what it is (the text field) to processes and emphasize experiences around how
relevant it is to report to developers through bug reports, how they may not fix things correctly and
how a lot of time goes into retesting and regression testing.
After the listing of ideas (and assumptions, there was a lot of that), I opened a web page on my
computer with a text field and an ok button and had the group mob to explore, asking them to apply
their ideas on this. Many of the things they mentioned in the listing exercise just before immediately
got dropped - the piece of software and possibility to use it took people with it.
the application and what with the file it connects to. We generated ideas around automation, not
through the GUI but the file and discussed what kind of things that would enable us to test. When
asked to draw a conceptual picture of relevant pieces, they did good. There was more connections
to be found, but that takes either a lot of practice on exploring or more time to learning layers.
Again with the second exercise, I was left puzzled on what I observed. They had a lot of ideas as a
group on what to try, but less of discipline in trying that out of following what they had tried. While
they could talk of equivalence partitioning or boundaries, their actual approaches on thinking what
values are equivalent and learning more as they used the application left something to hope for.
The sources of actual data were interesting to see, “I want a long text” ended up as something they
could measure but unawareness immediately of an online tool that would help with that. They knew
some existed but did not go to get those. It could have been a priority call, but they also did not talk
about doing a priority call. When the application revealed new functionality, I was making a mental
note of new features of the text box I should test. And when that functionality (ellipsis shortening)
changed into another (scroll bars), I had a bug in mind. Either they paid no attention, or I pointed
that out too soon. Observation and reflection of the results was not as strong as idea generation.
The third exercise was a text field in a learning API, and watching that testing unfold was one of
the most interesting ones. One in the group quickly created categories of three outputs that could
be investigated separately. This one was on my list because the works right / wrong is multifaceted,
and in the perspective of where the functionality would be used and how reliable it would need to
be. Interestingly in the short timeframe we stick with data we could easily generate, and this third
one gave me a lot to think about as I made later one of my teams’s developers test it, getting them
even stronger into testing an output at a time, and insisting on never testing an algorithm without
knowing what it includes. I regularly test their algorithms of assessing if the algorithm was good
enough for the purpose of use, and found that the discussion was around “you shouldn’t do that,
that is not what testers are for”.
The session gave me a lot of food for thought. Enough so that I will turn this into a shorter session
teaching some of the techniques of how to actually be valuable. And since my conference tracks
planned are already full, I might just take an extra room for myself to try this out as the fourth
track.
Exploring Gilded Rose
There is a lot of talk around testing—who will do it, when it needs to happen, boxes it needs to fit
in—yet not enough on the actual testing. This is the first article in the series of looking at software
to test, and figuring out how to test it. This article is based on the experiences I’ve had watching
people test as I coach and teach them using these examples.
Requirements Specification
Priming With Information Sources and Tools 44
But there’s also other sources you can turn your attention to:
• Code. It “works in production” now and you can look at the implementation. If Java isn’t your
cup of tea even if I use it while I teach this, Emily has been nice to provide it with tons of other
languages.
• Unit test. The one unit test gives a starting point of how to execute the code so that you don’t
need to figure that out.
• IDE with visual code coverage. Code and unit test in an environment where you can start
working on it, with a code coverage tool. I use Eclipse with Code Coverage as I just like the
visual nature of it showing green, yellow and red for the branches.
• Ideas of the domain. You have past experiences of what makes sense for a shop and inventory
management system. You have ideas of what inputs are meaningful, and what could be
confusing. Everything you’ve learned about what makes software worthwhile is with you.
To make the exercise slightly more tester friendly and approachable in coaching people who never
work with code, I extracted a method out of the original unit test.
The Test
If you want to try things out before spoilers, pause here and go do the exercise. Figure out what your
test cases for it look like and why they are the way they are.
to write test cases based on the specification without running a single test. I expect you to design
your tests as you go and allow you to learn rather sooner than later.
Unlike for me right now writing this article after having done the exercise, you are now at a time you
know the least. You know there’s two information sources and either specification or code could
be your starting point. If you are a tester by trade, you are likely to lean towards the specification
and if you are a developer by trade, you are likely to lean towards the code and coverage tools.
As the exploratory tester, you are on the driver seat. You get to choose which way you go. And any
mix is possible. There is no recipe. But there is options.
Just Try It
You could just forget about the specification for now, as well as not read the code that implements
this, and start playing with values you can enter into the CheckItem-method. It takes three inputs:
If we didn’t look at the specification, deducting this much info out of the interface is unlikely. We
would just see it takes text and two numbers. But that is enough to play with it! This brings you to
the problem with least structure, highest chance of getting confused and highest chance of learning
something outside the spec and the code.
You could look at the problem with the simple ideas around the inputs. What if the input is really
really long? What if the number is really really big? Oo, negative numbers? Special characters? All
the things forbidden? Hey, there’s numbers that are special: what if your input is 00100, is that 100
or something different?
The Test
There has been days of going into doing the exercise where this test fails, because I accidentally
cleaned up more than I should after the previous run through the exercise.
Priming With Information Sources and Tools 47
As we are exploratory testing, we learn that the interface provided is good for us to go further. We
learn that the tool reports us with green when a test is given that passes. We might even read the test
to figure out that it says that when we start with item named “Any”, no days to sell it and quality
of zero, the quality isn’t changing anywhere.
The real choice is actually to realize they are all different dimensions and for properly testing this,
some work on all might need to happen. Some tracking of coverage on all of them would need to
happen. Some discipline in not abstracting results of one to fully cover the results of another would
need to happen.
What I often see with the choice of the second test is that some people choose to just pay attention
to the code, and end up missing out on all the problems the specification leads you to uncover.
Some people choose to pay attention only to the specification and report problems that aren’t really
problems and fail to cover the code. And some people just don’t feel like they are empowered to
add anything beyond the given artifacts, which is detrimental to their ability to uncover yet another
category of problems.
Priming With Information Sources and Tools 48
By the time they were done, they had worked significantly. Yet they called done before it was time.
No cleaning up the names, no looking for rules they might have missed.
ApprovalTest code
If you miss the copy-pasteable example of this, I put in a gist⁶. You may notice I needed to do one
change to the original method so that the returning object would have a toString() to write to file.
What was object type GildedRose in the first example, is no object type Items in the latter as it
already had the necessary toString() defined.
With the 41616 tests, I have now a list of things I can verify with specification. Obviously I would
sample heavily over checking them all. But with then visible, I can run into problems serendipitously.
I can notice that for
[Sulfuras, Hand of Ragnaros, 27, 23] ⇒ Sulfuras, Hand of Ragnaros, 27, 23
the second value, sellin, isn’t in fact changing. I could visually and conceptually compare it to another
item
[Foo, 1, 10] ⇒ Foo, 0, 9
Seeing that for all others but the legendary item Sulfuras, as specified, “never has to be sold” in
requirements means the sellin date won’t be changing.
Code coverage
I mentioned code and coverage earlier, and for including those in my exploration, my test
environment has a coverage plugin installed.
With already an individual test, I can see coverage in percentages.
Coverage numbers
Be careful though, the percentages here are line coverage - you get to 100% line coverage with many
branches not yet covered. Thus it is handy that the tool used has another way of looking at things,
color coding lines to reflect where branches have been covered.
⁶https://gist.github.com/maaretp/2ec5eb9e38b9d9b1758f98e0bdb016ed
Priming With Information Sources and Tools 50
To use coverage, you will need to read a bit of code. But reading it requires you to pick up texts that
are meaningful (the names of items you sell) and numbers that are meaningful (the values where
behavior is changing). If you feel lazy on the thinking side, a good rule for seeing a number is the
Boundary principle: choose the number, something just a little smaller and just a little larger. Adding
an extra test and seeing what happens often both makes your exploration faster, but also enables
serendipity - lucky accident of running into something your careful design isn’t leading you to, at
least not yet.
• First test was a poor choice leading to long-term confusion, we could either choose differently
or pay attention to what we really know more actively.
• Any coverage will do, some here some there and testing is done! That is true, but tracking
how much done are you is a big part of testing. Even the code coverage can fool you because
the number shows line coverage and the colors show branch coverage. Calling it done on line
coverage left out lines leading to new branches.
Priming With Information Sources and Tools 51
• Naming coverage dimensions isn’t a thing everyone does, they didn’t. Conceptualizing code,
specification, environment and risk coverage is a necessary thinking model.
• Code coverage can be achieved without proper asserts and gives a very false sense of security.
You don’t even need to assert values of quality for the 16 tests above to have them still run to
100% branch coverage.
• Problems against specification were all assumed distinct problems, no grouping around the fact
that there was full areas of “I expect input validation” that were not implemented anywhere.
• Specification having shorthand like saying “Sulfuras” instead of “Sulfuras, the Hand of
Ragnarok” isn’t a major problem with the specification even if it bit them in the exercise. Best
of specifications are helpful, yet incomplete. Best of testers using specifications don’t need them
to be complete to do complete testing.
• When results did not match the specification, quickly jumping to conclusion that we are testing
a buggy software which wasn’t the case. The models to pinpoint whether problem could be
in my tests that I have control over were not in place. We practiced many rounds of “is there
another test we could do that would give us a second data point to verify we understood the
requirement”.
• One test one requirement isn’t a thing. They are a messy network of dependencies.
There is no easy recipe for testing any application. Stop to think. Approach from different angles.
Check and double-check. And don’t hide in your corner, maximize your chances of getting to the
right information by working with the others.
Session Charter: Explore EPrimer focusing on two kinds of documentation as output: test
automation you can run (using e.g Robot Framework) and a mindmap. Time: 1 hour plus
learning time for test automation tool if you have no experience and no expert available
answering your questions in the moment.
⁷https://eviltester.github.io/TestingApp/apps/eprimer/eprimer.html
Priming With Information Sources and Tools 52
Breakdown of activities
Whenever we are doing exploratory testing, we get to make choices of where we use our limited time
based on the best information available at the time of testing. We are expected to intertwine various
activities, and when learning, it may be easier to learn one activity at a time before intertwining
them.
If you think back to learning to drive (while stick gear was a thing), you probably have ended up
in an intersection, about to move forward and your car shutting down as intertwining your actions
with the gear and pedals were not quite as they should. You slowed down, made space for each
activity and got the car moving again. Exploratory testing is like that, you control the pace and
those who have practiced long will be intertwining activities in a way that appears magical.
For this testing target, we had multiple activities we needed to intertwine (learn / design / execute):
* Quickly acquiring domain knowledge: no one knew what eprime is, and we had our choice of
reading about it. * Acquiring functional knowledge: using the application and figuring out what it
does. * Creating simple scripts with multiple inputs and outputs: using same test as template for data-
driven helps repeat similar cases in groups. * Identifying css selectors: if you wanted test automation
scripts, you needed to figure out what to click and verify and how to refer to those from the scripts.
* Controlling scope of tests: see it yourself, see it blink with automation, repeat all, repeat only the
latest. * Creating an invisible or visible model: Seeing SFDPOT (Structure, Function, Data, Platform,
Operations, Time) to understand coverage in selected or multiple dimensions * Cleaning up test
automation: Improving naming and structuring to make more sense than what was created in the
moment. * Using the application: Making space for chances to see problems beyond the immediate
test * Identifying problems: Recognizing problems with the application. * Documenting problems:
Writing down problems in either test automation or otherwise. * Working to systematic coverage:
Pick a dimension, and systematically cover it learning more on it. * Reading the code: We had the
code and we could read it. That could add to our understanding.
Priming With Information Sources and Tools 53
Taking another two hours on top of the two hours on cleaning up the results. I summarized final
results like this:
The app isn’t completely tested, as the exercise setting biased us towards documentation.
Examples of activities
Quickly acquiring domain knowledge. Reading the specification of eprime. Focusing on examples
of eprime. Refreshing knowledge of English grammar around the verb “to be” e.g. 5 basic forms of
verbs and 6 different types of verbs, or 6 categories of verbs - all things I googled for as I am writing
this. While the specification tells what knowledge was probably used to create the application, there
is domain knowledge beyond what people choose to write down in specification.
Acquiring functional knowledge. Using the application. Asking questions about what is visible, par-
ticularly the concepts that are no obvious: ‘What is Possible Violations?”. Seeking data demonstrating
it could work. Seeking large data to demonstrate functions through serendipity.
Creating simple scripts with multiple inputs and outputs. Writing test automation that allows for
giving multiple input and output values as parameters. Getting into the tool and into using the tool.
Identifying css selectors. Getting to various values with code, understanding what is there in different
functions to click and check. Feeling joy systematic ID use making the work easier. Recognizing
conflicts in UI language and selector language.
Controlling scope of tests. Moving tests to separate files. Commenting out tests that already work.
Running tests one by one.
Creating an invisible or visible model. Ensuring we see all things work once before we dig deeper in
any individually. Creating a map of learning in the last minutes of the session. Writing down notes
of what we are seeing as either test automation or other types of documents.
Cleaning up test automation. Rename everything named foo at time when we knew the least.
Comment out things to focus on the next thing getting done efficiently. Using domain concepts
as names of collections.
Using the application. Spending time using the application to allow for serendipity. Observing look
and feel. Observing selected terminology.
Identifying problems. Seeing things that don’t work. Like visual of it that is very bare-bones. Or line
breaks turning valid positives into false negatives.
Documenting problems. Writing these down in test automation. Figuring out it we want to leave it
passing (documenting production behavior) or failing (documenting bugs). Remembering issues to
mention. Writing them down as notes. Writing a proper bug report.
Priming With Information Sources and Tools 54
Working to systematic coverage. Stopping to compare models to how well those are covered. Creating
a visual model. Covering everything in the specification. Covering all visible functionality.
Reading the code. Closing the window that has the code as it gets in the way of moving between
windows. Reading the code to see how concepts were implemented.
Some Reflections
Every time I teach exploratory testing, I feel I should find ways of teaching each activity separately.
There is a lot going on at the same time, and part of its effectiveness is exactly that.
In the group, someone suggested we could split the activity so that we first only document as
test automation, not caring about any of the information other than what is true right now in the
application. Then we could later review it against specifications and domain knowledge. That could
work. It would definitely work as one of the many mixes when exploring - change is the only
constant. This split is what approval testing is founded on, yet I find that I see different things when
I use the application and create documentation intertwined, than receiving documentation that I
could review. One night in between the actions is enough for me to turn into a different person.
Mindmap of Exploration
The robot tests from the two sessions combined with cleanup are available on github.⁸
⁸https://github.com/maaretp/exploring-robot-framework/tree/master/eprime
Python Primer for Exploring an API
With first of our release, I taught the most straightforward way I could to test an API for my summer
trainee. I gave them a URL (explaining what a URL is), showed different part of it indicated where
you connected and what you were asking for and ended up leaving office for four hours letting
them test for the latest changes just as other people in the team wanted to get out of office for their
summer vacation. They did great with just that in my absence, even if they felt the responsibility of
releasing was weighing on them.
No tools. No postman. Just a browser and an address. Kind of like this: http://api.zippopotam.us/us/90210
The API we were testing returned a lot more values. We were testing 20000 items as the built-in limit
for that particular release, and it was clear that the approach to determine correctness was sampling.
Two weeks later, today we returned to that API, with the idea that it was time to do something more
than just looking at results in the browser.
As we were typing in import requests, I explained that we’re taking a library into use. Similarly
I explained print(requests.get("http://api.zippopotam.us/us/90201")), forgetting the closing
parenthesis at first and adding it on a line after.
With the 200 response, I explained the idea of this code meaning it was ok, but we’d need more to
see the message we had earlier seen in a browser, and that while we could also use this for testing,
we’d rather move to writing our code to a file in an IDE.
The API we were playing with had a lot more pieces. With environments, names, id’s, dates, limits
and their suffixes in the call we had a few more moving parts to pull out with the very same pattern.
Python Primer for Exploring an API 58
As we were now able to run this for one set of values, our next step was to see it run for another
set of values. On our API, we’re working on a data-specific bug that ends up giving us a different
status code of 500, we wanted to move for the idea of seeing that here.
Making the status code visible with
print(response.status_code)
we started our work to have calls of the whole_thing where it wasn’t what we started with but had
multiple options.
#rest_of_it ="us/90210" rest_of_it = "fi/00780"
Every option we would try got documented, but the state of changing one into a comment and
another into the one we would was not what we’d settle for.
We wanted two things: * a method that would take in the parts and form the whole_thing for us *
a way of saving the results of calls
We started with keeping a part of the results introducing pytest writing that into requirements.txt
as second line.
requests pytest
Again we clicked an ok adding what our environment was missing as Pycharm pinged us on that,
and saved the response code codifying it into an assert. We remembered to try other values to see it
fail to trust it in the first place.
assert response.status_code == 200
Us still wanting the two things above, I interrupted our script creation to move us a step in a different
direction.
1 def setup_class(self):
2 pass
3
4 def teardown_class(self):
5 pass
6
7 def setup_method(self):
8 pass
9
10 def teardown_method(self):
11 pass
12
13 def test_one(self):
14 assert True
representing us giving two pieces of text that would end up forming the changing parts of the
address.
A little red bulb emerged on the IDE next to our unimplemented method (interjecting TDD here!)
and we selected Define function from the little menu of options on the light bulb. IDE created us a
method frame. def define_address(param, param1): pass
We had already been through the idea of Refactor | Rename coming up with even worse names and
following the “let’s rename every time we know a name that is better than what we have now”
principle. I wouldn’t allow just typing in a new name, but always go through Refactor to teach the
discipline that would be benefiting from the tooling. Similarly, I would advice against typing whole
words but allowing IDE to complete what it can.
We moved the piece of concatenating two parts together into the method (ours had a little more
parts than the example). def define_address(part1, part2): whole_thing = part1 + part2
return whole_thing`
Python Primer for Exploring an API 60
and were left with a test case where we had to call the method with relevant parts of the
address def test_one(self): # rest_of_it ="us/90210" response = requests.get(define_-
address("http://api.zippopotam.us/", "fi/00780")) print(response.text) assert response.status_-
code == 200 The second test we’d want as comment in the first became obvious, and we created a
second test. def test_two(self): response = requests.get(define_address("http://api.zippopotam.us/",
"us/90210")) assert response.status_code == 200
1 approvaltests
2 pytest-approvaltests
We saw a file TestClass.test_one.received.txt emerge in our files, and after visually veri-
fying it captured what we had seen printed before, we renamed the file as TestClass.test_-
one.approved.txt. We run the tests again from the IDE to now see them pass, edited the approved-
file to see it fail and corrected it back to verifying our results match.
As finalization of the day, we added verification on our second test, again visually verifying and
keeping the approved file around.
1 def test_one(self):
2 response = requests.get(define_address("http://api.zippopotam.us/", "fi/00780"))
3 verify(response.text)
4 assert response.status_code == 200`
And finally, we defined approvaltests_config.json file to include information where the files
approvaltests create should go ‘ { “subdirectory”: “approved_files” } “‘
These steps give us what we could do in a browser, and allow us to explore. They also help us save
results for future with minimal effort, and introduce a baseline from which we can reuse things
we’ve created.
Exploratory Testing an API
This article was published in Ministry of Testing Testing Planet in 2016. Appropriate pieces of it will
find their place as part of this book.
As an exploratory tester I have honed my skills in testing products and applications through a
graphical user interface. The product is my external imagination and I can almost hear it whispering
to me: “Click here… You want to give me a different input… Have you checked out the log file I’m
producing?”
Exploratory testing is a systematic approach to uncovering risks and learning while testing. The
whispers I imagine are heuristics, based on years of experience and learning of how I could model
the product in relevant ways to identify information relevant to stakeholders. While the product is
my external imagination when I explore, I am my programmer’s external imagination when they
explore. They hear the same, unspoken whispers: “You’d want me to do this… I guess I should then.”
and they then become better testers.
I’ve only recently started applying this skillset on APIs - Application Programming Interfaces. An
application programming interface is a set of routines, protocols, and tools for building software and
applications. What triggered this focus of exploration effort was an idea to show at a conference how
testing something with a code interface is still very similar to testing something with a GUI.
With an API call, I can just fill in the blanks and figure out how the API sits in the bigger picture.
There should be nothing that stops me from exploring through an API, but why haven’t I done
it before? And then as I started exploring an API with a testing mindset, I started seeing APIs
everywhere, and finding more early opportunities to contribute.
covered by detailed test cases. I’ve lived with Agile ideals long enough to have moved to the idea
that whatever is worth documenting in detail, it is probably worth documenting as test automation.
This way of looking at testing tends to focus on what we know.
When we approach testing as artifact creation, our focus is primarily on solving the problem of
creating right artifacts: what kinds of things would be useful automated? Where are the low-hanging
fruit and what kind of automation would help us drive and support the development?
The test automation artifacts at best give us:
We need both sides of the coin. Exploratory testing is a process of discovery, and it is entirely possible
to discover information we did not have from extensive test automation using APIs as our external
imagination.
There’s inherently nothing in exploratory testing that requires we must have a user interface or
have finalized features available. Still often I hear people expressing surprise at the idea that you
can explore an API.
In addition, exploring an API is thought as something that is intended for programmers. And an even
more specific misconception is that exploratory testing could not use programming / automation as
part of the exploration - that there would be something inherently manual required for exploration.
We must, as software testers, help team members understand that we can explore software in a
variety of manual, automated and technical ways.
by a developer friend with significant reliance on the greatness of his unit tests, and I welcomed the
challenge to find problems through the means of exploratory testing.
ApprovalTests is a library for deciding if your tests pass or not, with a mechanism of saving a
result to a file and then comparing to the saved result. It also offers mechanisms of digging into
the differences on failure. It has extensive unit tests, and a developer who likes to brag about how
awesome his code is. The developer is a friend of mine and has a great approach to his open source
project: he pairs with people who complain to fix things together.
ApprovalTests have a couple of main connecting points.
• There are the Approvals that are specific to technology your testing. For example, my company
used ExcelApprovals that packaged a solution to problem of having different yet same results
with every run.
• And then there are the Reporters that are a way of saying how you want to analyze your tests
if they fail.
I personally know enough about programming to know to appreciate an IDE tool and the automatic
word completion feature. The one in Visual Studio is called Intellisense. It’s as if there is a GUI:
I write a few letters, and the program already suggests me options. That’s a user interface I can
explore, just as much as any other! The tools shows what the API includes.
Picture 1
Using the IDE word completion, I learn that Approvals has a lot of options in its API. Here is an
example where to test specific technologies with Approvals, you would want to make different
selections. Documentation reveals that Approvals.Verify() would be a basic scenario.
Exploratory Testing an API 65
Picture 2
I look at Reporters with the same idea of just opening up a menu, and find it hard to figure out what
in the list are reporters.
I later learn that it’s because of the word before, and that naming everything ReportWith would
help make the reporters more discoverable.
I also learn that the names can improve to include better their intent, for example some are supposed
to be silent - to run with continuous integration.
Picture 3
I go for online examples, and learn that they are images - not very user friendly. And I try to look for
in-IDE documentation, and learn it’s almost non-existent. I run existing unit tests to uncover they
don’t work at first run, but the developer fixes them quickly. And browsing through the public API
with the tool, I note a typo that gets fixed right away.
The API has dependencies to other tools, specifically test runners (e.g. nUnit and MSTest) and I want
my environment to enable exploring the similarities and differences with the two. Serendipitous
Exploratory Testing an API 66
order of installing the pieces reveals a bug in combination of using two runners in combination
with a delivery channel (Nuget). Over the course of testing, I draw a map of the environment I’m
working with, around ApprovalTests. The map is a source of test ideas on the dependencies.
I don’t only rely on the information available online, I actively ask for information. I ask the
developer what Approvals and Reporters do, to get a long list of things that some do and some
don’t - this becomes a great source for more exploratory testing. Like a checklist of claims, and a
great source for helping him tune up his user documentation.
Even a short exploration gave me ideas of what to dig in deeper, and issues to address for the
developer. Some additional sessions with groups in conferences revealed more problems, and showed
the power of exploratory testing on an extensively automation tested API.
5 - Usability of an API
There’s great material out there on what makes a good API. It’s really a usability discussion!
When using the different commands/methods, what if they would be consistent in naming and in
parameter ordering so that programmers using them would make fewer mistakes?
Exploratory Testing an API 68
What if the method signatures didn’t repeat many parameters of same type so programmers using
them would get mixed up in the order?
What if using the API incorrectly would fail compile-time, not only run-time to give fast feedback?
What if the methods would follow a conservative overloading strategy, an idea that two methods
with same name would never have the same amount of arguments so that users can confuse the
inputs? I had never heard of the concept before exploring an API, and run into the idea googling for
ideas of what people say that make APIs more usable.
There’s even a position in the world called Developer Experience (DX), applying the user experience
(UX) concepts to the APIs developers use and focusing on things like Time to Hello world (see it run
on your environment) and Time to Working Application (using it for something real). These ideas
come naturally with an exploratory testing mindset.
7 - Think Lifecycle
You’re probably testing a version you have just kindly received into your hands. There were probably
versions before and there will be versions after. The only software that does not change is dead. How
does this make you think about testing?
• Find the core of a new user’s experience and describe that clearly
• Add the deeper understanding of what (and why) the functionalities do into API documenta-
tion
• Clean up and remove things from automatically created API documentation
Exploratory Testing an API 70
• It’s not that I’m so smart, it’s I just that I stay with the problems longer (Albert Einstein)
• The more I practice, the luckier I get (Arnold Palmer)
I find a lot more insights digging in deeper than what is first visible. Manual repetition may be key
for this insight, even on APIs.
Your set of automated tests will require maintenance. When tests fail, you will look into those.
Choose wisely. Choose when you learn what wise means.
Summary
Exploring APIs gives you the power of early feedback and easy access to new skills closer to code.
I suggest you give it a chance. Volunteer to work on something you wouldn’t usually work on as a
non-programmer. You’ll be surprised to see how much of your knowledge is transferrable to “more
technical” environment.
Anchoring an Idea While Exploratory
Testing an API
One of the things we get to test is a customer oriented API. It’s particularly lovely test target for
multiple reasons:
• Read-only: It only gets data, and does not allow us to change data. Makes it simpler!
• Time-constrained on API level: You can tell dates as input and it does freeze time for test
automation purposes. You don’t have to play with concepts of today() and now().
• Limited and understandable UI level edits to data: There are some things we can change from
GUI that impact the API but they are fairly straightforward.
The main reason it brought us joy for testing today is that we found a bug on it a few weeks back
where particular combination returns 500 error code (Server error) where it should not, and we got
to start creating some tests back then to create a nice baseline for the time that bug would be fixed.
The long awaited message of bug fix arrived today, and the first thing we’d do is pull out the tests
we had automated the last round (asserts and approvals, I wrote about those earlier as we set the
project up). We ran the tests, expecting to see a fail for the assert for getting 500 for that bug. The
results surprised us.
We still had that test passing, but now we also had another test failing with 500. Instead of going
forward with the fix, we had momentarily gone backwards.
Not long after, we got to try again with a new version. This time it was just as we expected. Within
30 seconds of realizing the version was available, we knew that on the level we automated our tests
before, those were now matching today’s expectations.
For those of you concerned on the tests not running in CI, it is about the same time to go check they
are blue as we did not place these tests as ones blocking the pipeline. These tests weren’t designed
for the pipeline, they were designed as an entry point for exploratory testing where we could leave
some of them behind for the pipeline or for other purposes.
We quickly drafted our idea of what we would test and change today:
• Capturing and reviewing for correctness for the combination that we previously documented
as receiving the 500 response for that bug
• Ensuring we could see latest data after the most recent changes
• Having easily configurable control over dates and times we had not needed in our tests before
Anchoring an Idea While Exploratory Testing an API 72
Making some of the tests approval files smaller in size as long as they did not lose the idea of what we
were testing with them What turned out to be the most fun thing to test was the latest data. Starting
with that idea, we found multiple other ideas of what to test, including things around changing more
values on the data, and things around multiple overlapping limits. We needed to remind ourselves,
multiple times, that we still have not seen our starting idea in action, even if we had seem many
other ideas.
As a conclusion of today, we came to the importance of anchor, and remembering that anchor. If
writing it down helps, write it down. If having a pair that keeps you honest helps, have a pair.
Whatever works for you. But a lot of times, when we do some testing, we end up forgetting what
was the thing we set out to do in the first place. Anchoring an idea allows us to discover while we
explore, and still stay true to what we originally set out to do.
We ended up refactoring our test code a bit to make it more flexible for the ideas we had today,
and we discovered one test we wanted to keep for future. It started off with one name and concept,
yet though exploring we learned that what we wanted to keep for future was different to what we
wanted and needed to do today.
Great chance of pairing on API #ExploratoryTesting with my trainee as there was a major
change on the logic behind the API. Got to experience the ideas of tests we throw away,
tests we want to keep for later but for reasons other than we start with, and relying on
past tests.
Truth is, we always throw some away, and that is where I recognize learning and thinking is going
on. Can keep and should keep are two different things.
Reporting and Notetaking
Exploratory Testing. The wonderful transformation machinery that takes in someone skilled and
multidisciplinary and time, crunches whatever activities necessary and provides an output of
someone more skilled, whatever documentation and numbers we need and information about
testing.
What happens in the machinery can be building tools and scripts, it can be operating and observing
the system under test but whatever it is, it is chosen under the principle of opportunity cost and
focused on learning.
When the world of exploratory testing meets the world of test automation, we often frame same
activities and outputs differently. When a test automation specialist discusses reporting, it seems
they often talk about what an exploratory tester would describe as note taking.
Note taking is when we keep track of the steps we do and results we deliver and explain what we
tested to other people who test. Reporting is when we summarize steps and results over a timeframe
and interpret our notes to people who were not doing the testing.
Note taking produces: * freeform or structured text * screenshots and conceptual images * application
logs * test automation that can be thrown away or kept for later
Reporting produces something that says what quality is, what coverage is, how long what we say
now stays true, and what we recommend we would do about that.
Automation can take notes, count the passes and fails, summarize use of time. The application under
test takes notes (we call that logging) and it can be a central source of information on what happened.
When automation does reporting, that usually summarizes numbers. I find our managers care very
little for these numbers. Instead, the reporting they seek is releases and their contents.
When automation does log of test case execution, we can call that a report. But it is a report in scope
very different than what I mean by a report from exploratory testing - including automation.
Test Case Management Tools in
Exploring
Zephyr, in case you did not know, is a Jira Test Management extension. I dislike Jira, and I dislike
Zephyr. But what I like and don’t like does not change (well, immediately) the whole organization,
and I play within general bounds of organizational agreements. In this case, it means an agreement
that tests are documented in Zephyr - for some definition of tests.
This chapter is about how I play within those bounds, enabling exploratory testing.
• Steps. For some reason people still think tests have steps with expected values. If you don’t
know better, you might use these. DON’T.
• Mapping tests to releases. You can tell what test ticket connects with a particular Jira release.
It shows the structure of how testing usually progresses in relation to changes.
• Grouping. You can group tests inside releases into test suites. You have many reasons you might
want to group things. Zephyr calls mapping and grouping cycles.
• Run-time checklists. You can keep track of passes and fails, things in progress. You can do it
either on level of a group of tests or on an individual test. You have a whole own view to
making notes while testing on a particular test case, execution view. It seems to imagine all
your test needs in one place: bug reporting, steps, notes.
What I Bring In
When I document my plans of testing, I create a few kinds of tests: * [Explore] <write a one line
summary here> These tests can be for the whole application like “Gap analysis exploration - learn
all the problems they don’t yet know”, or a particular purpose like “Release”, or an area of particular
interest like “Use for people with disabilities”. If I can get away with it, I have only one test case
titled “[Explore] Release” and I only write notes on it at time of making a release. What this assumes
though is that release is something more continuously flowing rather than one final act in the end
- agile as if we meant it. * [Scenario] <write a one line summary here> These tests are for very high
Test Case Management Tools in Exploring 75
level splitting of stakeholder perspectives I want to hold space for. They are almost like the ones
I mark [Explore] expect that they all together try to summarize remembering the most important
stakeholders and their perspective in the product lifecycle. These are in the system context, regardless
of what my team thinks their component delivery responsibility has been limited to.
* [Feature] <write a one line summary here> These tests I use when I have bad or non-existent
documentation on what we promise the software will do. These tests all together try to summarize
what features we have and try to get to remain, but as a high level checklist, not going into details of
it. These are in the context of the system, but more towards the application my team is responsible
for.
I use states of these tests to indicate scope ahead of me.
If a test is Open (just like a regular Jira ticket), it is something I know we expect to deliver by a major
milestone like a marketing release all the little releases work towards, but I have not seen a version
in action we could consider for the major milestone scope. It reminds me to ask if we have changed
our mind on these.
If a test is Closed, it is still alive and used. but it is something where we have delivered all the way
to production some version of it and we intend to keep it alive there.
If I can get away with one test case, that is all I would do. There are many reasons for me not to be
able to get away with it: a newer colleague we need a shared checklist with, me needing a checklist
and creating it here with minimal extras, or auditing process that would not be fulfilled with just
that one ticket of [Explore] Release.
The updating of test status is part of release activities for me. Someone needs to create a release in
Jira, which usually happens when the previous release is out. For that release, I add at most two
Cycles: * Pre-Release Testing * Release Testing
Again, if I can get away with it, I have only one: Release Testing and within in, I have only one test:
[Explore] Release that I mark passed and write notes if I have something useful to say. Usually the
useful thing for me to say is “release notes, including scope of changes is available here <link>”.
The way testing works for me is that I see every pull request and nothing changes outside pull
requests. I test selected bits and pieces of changes, assessing risk in the moment. I also have a set of
test automation that is supposed to run blue/green (pick your color for ‘pass’) that hunts down need
of attending to some detail. And I grow the set of automation. If you need ‘proof’ of passing for a
particular release, we could in theory get that out of version control but why would you really want
that?
The Pre-Release Testing Cycle, if it exists, I fill it when I think though what happened since last
release and what still needs to happen before the next one and I drag in existing tests from all
three categories [Explore], [Scenario] and [Feature] to be a checklist. What this cycle contains tells
about themes and features I found myself limiting to. And when a Pass on the cycle isn’t sufficient
documentation, I can always comment the test ticket.
My use of Zephyr is very different to my colleagues. Perhaps also to your use?
Process
This section collects together topics around process. How to frame software development in general.
Feature and Release testing
Back in the day, we used to talk about system testing. System testing was the work done by testers,
with an integrated system where hardware and software were both closer to whatever we would
imagine having in production. It usually came with the idea that it was a phase after unit and
integration testing, and in many projects integration testing was same testing as system testing but
finding a lot of bugs, where system testing was to find a little bugs and acceptance testing ended
up being the same tests but now by the customer organization finding more bugs that what system
testing could find.
I should not say “back in the day”, as for the testing field certification courses, these terms are still
being taught as if they were the core of smartassery testers need. I’m just feeling very past the terms
and find them unhelpful and adding to the confusion.
The idea that we can test our software as isolated units of software and in various degrees of
integrated units towards a realistic production environment is still valid. And we won’t see some of
the problems unless things are integrated. We’re not integrating only our individual pieces, but 3rd
party software and whatever hardware the system runs on. And even if we seek problems in our
own software, the environment around matters for what the right working software for us to build
is.
With introduction of agile and continuous integration and continuous delivery, the testing field very
much clung to the words we have grown up with, resulting in articles like the ones I wrote back
when agile was new to me showing that we do smaller slices of the same but we still do the same.
I’m calling that unhelpful now.
While unit-integration-system-acceptance is something I grew up with as tester, it isn’t that helpful
when you get a lot of builds, one from each merge to master, and are making your testing way
through this new kind of jungle where the world around you won’t stop just so that you’d get
through testing that feature you are on on that build you’re on, that won’t even be the one that
production will see.
We repurposed unit-integration-system-acceptance to test automation, and I wish we didn’t. Giving
less loaded names to things that are fast to run or take a little longer to run would have helped us
more.
Instead of system testing I found myself talking about feature/change testing (anything you could
test for a change or a group of changes comprising a feature that would see the customer’s hands
when we were ready) and release testing (anything that we needed to still test when we were making
a release, hopefully just run of test automation but also a check of what is about to go out).
For a few years, I was routinely making a checklist for release testing:
Feature and Release testing 78
• Minimize the tests needed now, get to running only automation and observing automation
running as the form of visual, “manual” testing
• Split into features in general and features being introduced, shining special light to features
being introduced by writing user oriented documentation on what we were about to introduce
to them
From tens of scenarios that the team felt that needed to be manually / visually confirmed to running
a matrix test automation run on the final version, visually watching some of it and confirming
the results match expectations. One automated test more at a time. One taken risk at a time, with
feedback on its foundation.
Eventually, release testing turned into the stage where the feature/change testing that was still
leaking and not completed was done. It was the moment of stopping just barely enough to see
that the new things we are making promises on were there.
I’m going through these moves again. Separating the two, establishing what belongs in each box
and how that maps into the work of “system testers”. That’s what a new job gives me - appreciation
of tricks I’ve learned so well I took them for granted.
Training and Exploratory Tester
This summer gives me the perfect possibility - a summer intern with experience of work life outside
software and I get to train them into being a proper Exploratory Tester.
Instead of making a plan of how to do things, I do things from a vision, and adapt as I learn about
what the product team needs (today) and what comes easy for trainee trusted into my guidance.
Currently my vision is that by end of the summer, the trainee will: * Know how to work effectively
in scope of a single team as tester inside that team * Understand the core a tester would work from
and regularly step away from that core to developer and product owner territory * Know how to
see versatile issues and prioritize what issues make sense to report, as each report creates a response
in the team * Know that best bug reports are code but it’s ok to learn skills one by one to get
to that level of reporting ability - being available is second best thing * Understand how change
impacts testing and guide testing by actual change in code bases in combination of constraints
communicated for that change * Write test automation for WebUI in Jest + Puppeteer and Robot
Framework and take part in team choice of going with one or the other * Operate APIs for controlling
data creation and API-based verifications using Java, Python and JavaScript. * Understand how their
testing and test automation sits in the context of environments it runs in: Jenkins, Docker and the
environment the app runs in: Docker, Kubernetes and CI-Staging-Prod for complex set of integrated
pieces * Communicate clearly the status of their testing and advocate for important fixes to support
‘zero bugs on product backlog’ goal in the team * Control their own balance of time to learning
vs. contributing that matches their personal style to not require task management but leading the
testing they do on their own * Have connections outside the company in the community to solve
problems in testing that are hard to figure out internally
We got started this week, are are one week into the experience. So far they have:
• Reported multiple issues they recognized are mostly usability and language. I jumped on the
problems with functionality and reported them, demoing those enforced the idea that they are
seeing only particular categories now.
• Navigated command line, filesystem, Git, and IDE in paired setting and shown they pick things
up from examples they experience, repeating similar moves a day later from learning the
concepts.
• Skipped reporting for a language bug and fixed it with PR instead.
• Covered release testing with a provided one-liner checklist for the team’s first release.
• Provided observations on their mentors (mine) models of how I train them, leading me to an
insight that I both work hard to navigate on higher level (telling what they should get done,
and only after digging into exactly how to do it if they already don’t know that) and respond
questions with questions to reinforce they already know some of the stuff.
Training and Exploratory Tester 80
• Taken selective courses from Test Automation University on keywords they pick up as I explain,
as well as reading tool-specific examples and guidelines.
• Explained to me how they currently model unit - service - UI tests and mixed language set the
team has.
• Presented a plan of what they will focus on achieving next week with Jest-Puppeteer 1st case
with our application.
After the week, I’m particularly happy to see the idea of self-management and you leading your own
work but radiating intent is catching up. Them recognizing they can’t see all types of bugs yet is
promising as is their approach to learning.
Every step, I prepare them for the world where I won’t be there to guide them but they know how
to pull in help when they need it - inside the company and outside.