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.
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.
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:
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.
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)
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.
(a) Identify the fault.
findLast is implemented as a recursive function by implementing
@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
There are three
findLastRecursive functions white same signature.
We start the recursion with starting values: original
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
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
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
x and there are still integers in
(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.