We should find a way to prioritize and select a subset of inputs and outputs that will give us sufficient certainty about the correctness of the program. Although the number of possible program inputs and outputs is nearly infinite, some sets of inputs make the program behave the same way, regardless of the precise input value.
In the case of our example, for testing purposes, the input “abcd” with open
tag “a” and close
tag “d”, which makes the program return “bc”, is the same as the input “xyzw” with open
tag “x” and close
tag “w”. You change the letters, but you expect the program to do the same thing for both inputs. Given your resource constraints, you will test just one of these inputs (it does not matter which), and you will trust that this single case represents that entire class of inputs. In testing terminology, we say that these two inputs are equivalent.
Once you have identified this class (or partition), you repeat the process and look for another class that will make the program behave in a different way that you have not yet tested. If you keep dividing the domain, you will eventually identify all the different possible classes (or partitions) of inputs.
A systematic way to do such an exploration is to think of the following:
- Each input individually: “What are the possible classes of inputs I can provide?”
- Each input in combination with other inputs: “What combinations can I try between the
open
andclose
tags?” - The different classes of output expected from this program: “Does it return arrays? Can it return an empty array? Can it return nulls?”
I find it easiest to start with individual inputs. Follow me:
str
parameter —The string can be any string. The specification mentions the null and empty cases; I would have tested those anyway, because they are always good exceptional test cases. Given that this is a string (which is basically a list of characters), I will also test what happens if the string has length 1.a) Null stringb) Empty stringc) String of length 1d) String of length > 1 (any string)open
parameter —This can also be anything. I will try it with null and empty, as I learned from thestr
parameter that those cases are special in this program. I will also try strings with length 1 and greater than 1:a) Null stringb) Empty stringc) String of length 1d) String of length > 1close
parameter —This parameter is like the previous one:a) Null stringb) Empty stringc) String of length 1d) String of length > 1
Once the input variables are analyzed in detail, we explore possible combinations of variables. A program’s input variables may be related to each other. In the example, it is clear that the three variables have a dependency relationship. Follow me again:
(str,
open,
close)
parameters—open
andclose
may or may not be in the string. Also,open
may be there, but notclose
(and vice versa).a)str
contains neither theopen
nor theclose
tag.b)str
contains theopen
tag but not theclose
tag.c)str
contains theclose
tag but not theopen
tag.d)str
contains both theopen
andclose
tags.e)str
contains both theopen
andclose
tags multiple times.
Note that this thought process depended on my experience as a tester. The documentation does not explicitly mention tags not being in the string, nor does it mention the open
tag being present but the close
tag not. I saw this case because of my experience as a tester.
Finally, we reflect on the possible outputs. The method returns an array of substrings. I can see a set of possible different outputs, both for the array itself and for the strings within the array:
- Array of strings (output)a) Null arrayb) Empty arrayc) Single itemd) Multiple items
- Each individual string (output)a) Emptyb) Single characterc) Multiple characters
You may think that reflecting on the outputs is not necessary. After all, if you reasoned correctly about the inputs, you are probably exercising all the possible kinds of outputs. This is a valid argument. Nevertheless, for more complex programs, reflecting on the outputs may help you see an input case that you did not identify before.
Leave a Reply