TL;DR
In the previous post, we presented Exercise On Software Testing Limitations And Terminology On Elixir Function. In this post, we explain answers to this exercise. We will introduce you to software testing based on the remarkable book, Introduction To Software Testing by Paul Ammann and Jeff Offutt.
Shotgun Answers
AST BBST Foundations course teaches us how to properly read a question and answer only what is asked. When students do not understand the question, they often use the “Shotgun” answering technique.
The student correctly answers what it knows, but the topic was not asked in the question.
Question One
For what do testers use automation?
Let’s open the book on page 11.
Additional information to answer. It is not an answer but clarifies the answer.
In software development, we have two types of tasks:
- Revenue
- Excise
For example, in Elixir, creating a function with business logic is a revenue task, writing test code for that function is a revenue task. Getting information about code coverage for function tests is an excise task.
Answer on “For what do testers use automation?”
Excise tasks are automation candidates. Software testing has a lot of excise tasks comparing to other software development activities.
Question Two
Answer on “What are the limitations of automation?”
When the excise task compares expected and actual results of a test script, the obvious limitation is that we check only variables programmed in the script.
Results of function coverage with function tests could not give an answer on missing code coverage (features that are not implemented)
Question Three
Below are four Elixir faulty programs. Each includes a test case that results in failure. Answer the following questions about each program.
We are only answering for function. findLast
(a) Identify the fault.
findLast
is implemented as a recursive function by implementing findLastRecursive.
Module attributes @moduledoc
and @doc
are documentation, while @spec
is a module attribute that defines the type of function input and output parameters. The function has two input parameters: a list of integer numbers and y
an integer that we are looking for. The return parameter is the index of the last element in the list x
that is equal to y
.
There are three findLastRecursive
functions white same signature.
We start the recursion with starting values: original x
and y
and index is set to 0 because this is the index of the list x
first element.
Their order is important because the function call order is top/down in Elixir. We use function signature pattern matching. For example, defp findLastRecursive([], _y, _index), do: -1
it is executed only when we reach an empty list. The other two values are not important in that case. This is the recursion stop function, and we return -1 because we know that y
was not found in x
.
In defp findLastRecursive([head | _tail] = _x, y, index) when head == y, do: index
we use list operator [ head | tail]
that breaks list x
into first list element head
and tail
is the rest of the list:
[head | tail] = [1, 2, 3]
head = 1 tail = [2,3]
This is what makes recursion possible.
when
is a function guard, and if it is true
that function is called. That means when we found the first match, we finish the recursion and return the current index.
And this is the fault
in our function. It creates a functioning error
state, and that is exit form recursion when we still could have list x
elements to search.
(b) If possible, identify a test case that does not execute the fault.
x = [] y = 3
(c) If possible, identify a test case that executes the fault but does not result in an error state.
x = [1, 2, 3] y = 3
(d) If possible, identify a test case that results in an error but not a failure. Hint: Don’t forget about the program counter.
x = [1, 2, 3] y = 2
(e) For the given test case, identify the first error state. Be sure to describe the complete state.
The first error state is when we match y
in x
and there are still integers in x
.
(f) Fix the fault and verify that the given test now produces the expected output.
In this gist revision, you can see all the details.
We added to findLastRecursive
a new parameter, result
, with a starting value of -1.
When we get to []
we return result
. We set result with the current index
value and move further through the list. When there is no match, we use current result
value and move along with the list values.