In this example, we're going to start from an informal specification, and the
specification is the one shown here in file spec.txt. This is the
specification for the maintenance function in a specific system. So what we're
doing is that we're taking the description of the functionality of a system,
and we're building a model, in this case a final state machine
for it. And there is no need to look at all the details
for this specification, but I want to point out that if you
look at the way the specification is written, we can identify specific cases
that we need to take into account. Like here if something
happens, something else will follow. Again, if something happens something else
will follow. So we have multiple choices here. Here will determine
the next steps and so on. So all we have to
do is to go through this process, identify these cases and
then build a machine that represents these cases. For the spec
that we just consider this is the state machine that will
result. Again there is no need to go through all the details,
but what I want to point out is that we have
a set of states. So for instance, we have state zero,
which is no maintenance, and if a request comes in, the
system will move, and the system wait for pickup. Then if
the pickup actually occurs, the system will move to the repair
state, and so on and so forth. So this is just
a more systematic representation of what was in the former specification.
And I will argue that this is much easier to understand at
least for somebody who has to develop tests for this system. In
fact what we're going to see next is how we can go from that
representation to a set of test cases. And the way which we do
it is by covering the behaviors represented by defining state machine. And we
can decide how we want to cover them. For example we might want
to cover all the states. So we might want to identify paths in
the state machine that go through all the states in the machine. Like
the one I just draw or this one, this one and this one.
So if we consider these four test cases, we can see that all the
states in my system or at least all the states that I have identified
are covered. I might want to go a little further, and decide that I
don't only want to cover all of the states, but I want to cover, all
of the transitions, because, it makes sense to visit a state, when coming from
different states. And, if I want to do that, and I look at the
test cases that I generated so far, I can see that there is one
transition, the one here, that is not covered. And, the same can be said for
the two transitions here. So what I can decide to do is
to generate another test case, that covers those or extend an existing one.
For instance, I could extend this test case by adding a visit to
the state, before going back to these two. Alternatively, I could also generate
new test cases, such as this one. To cover the missing transitions.
And once I have these test cases, I can express them in a
clearer way by simply specifying what are the states that they cover. I'm
just going to give you a couple of examples. Say, if we look
at the last one that I added, which will be test case
number five, I just need to specify that it will go through state
zero, which is this one, five, which is this one, six, and
then back to zero. And I can do the same for the other
test cases. So this will be my complete set of test cases.
So the bottom line here is that it is much harder to build
a set of test cases that will cover the behavior of an informal
description. But by going through a model, so by building in this case,
a finite state machine for that description, we can, in a much easier way, see
what the behaviors of interest of the system
are, and try to cover them. And there
is again in the spirit of breaking
down a complex problem into smaller steps that
we can better manage, which in the end,
results in a more efficient and effective testing.