debugging meets testing in erlang

55
Debugging meets testing in Erlang Salvador Tamarit, Adrián Riesco, Enrique Martín-Martín, Rafael Caballero (U. Complutense & U. Politécnica, Madrid, Spain) 10th International Conference on Tests & Proofs TAP 2016 5-7 July 2016, Vienna, Austria

Upload: others

Post on 14-Nov-2021

6 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Debugging meets testing in Erlang

Debugging meets

testing in ErlangSalvador Tamarit, Adrián Riesco,

Enrique Martín-Martín, Rafael Caballero

(U. Complutense & U. Politécnica, Madrid, Spain)

10th International Conference on Tests & Proofs TAP 2016

5-7 July 2016, Vienna, Austria

Page 2: Debugging meets testing in Erlang

Motivation

2 10th International Conference on Tests & Proofs

Outline

Unit Testingin Erlang

Declarativedebugging

Our proposal Conclusions

Page 3: Debugging meets testing in Erlang

Motivation

3 10th International Conference on Tests & Proofs

Outline

Page 4: Debugging meets testing in Erlang

DebuggingMost labor-intensive task in software development

1)Many different computations to consider, correct and wrong

2) Complexity: compare Intended meaning of the each piece of codeThe value actually computed

4 10th International Conference on Tests & Proofs

MotivationThinking about the rôle of debugging

Page 5: Debugging meets testing in Erlang

Debugging Compare intended and computed values

5 10th International Conference on Tests & Proofs

MotivationThinking about the rôle of debugging

f(x) = x2 f(3) = 9

Page 6: Debugging meets testing in Erlang

Debugging Sometimes comparing expected and obtained resultsis not so easy!

6 10th International Conference on Tests & Proofs

MotivationThinking about the rôle of debugging

Page 7: Debugging meets testing in Erlang

DebuggingMany questions!

7 10th International Conference on Tests & Proofs

MotivationThinking about the rôle of debugging

Page 8: Debugging meets testing in Erlang

Debugging Goal: find an unexpected result

8 10th International Conference on Tests & Proofs

MotivationThinking about the rôle of debugging

Page 9: Debugging meets testing in Erlang

Debugging sessions Intense reflection about the code deep understanding of the program

9 10th International Conference on Tests & Proofs

MotivationThinking about the rôle of debugging

Page 10: Debugging meets testing in Erlang

Debugging What happens with all this knowledge once the bughas been found?

10 10th International Conference on Tests & Proofs

MotivationThinking about the rôle of debugging

Page 11: Debugging meets testing in Erlang

Is debugging really part of the software development life cycle?

11 10th International Conference on Tests & Proofs

MotivationThinking about the rôle of debugging

?

Page 12: Debugging meets testing in Erlang

12

Initial

Requirements DevelopmentTests

New functionalities

Additional

Requirements

New

Development

New

Tests

Example: Testing

MotivationThinking about the rôle of debugging

10th International Conference on Tests & Proofs

Page 13: Debugging meets testing in Erlang

13

Initial

Requirements DevelopmentDebugging

sessions New functionalities

Additional

Requirements

New

Development

New

Debugging

sessions

What about debugging?

MotivationThinking about the rôle of debugging

10th International Conference on Tests & Proofs

Page 14: Debugging meets testing in Erlang

Our Goal Integrate debugging in thesoftware development life cycle

14 10th International Conference on Tests & Proofs

MotivationThinking about the rôle of debugging

HowTo

1)Debugging sessions generate tests

2) Tests used during debugging sessions

Page 15: Debugging meets testing in Erlang

Motivation

15 10th International Conference on Tests & Proofs

Outline

Declarativedebugging

Page 16: Debugging meets testing in Erlang

16 10th International Conference on Tests & Proofs

Declarative debugging

Initial symptom: unexpected result detected by the user

Automatically generates a computation treeNode: Computation steps with its resultChildren: Subcomputations needed to obtain the result at the parent nodeRoot: initial symptom

Validity: The user determines the validity of the nodes

Goal: Find a buggy node, an invalid node with valid children incorrect piece of code

Page 17: Debugging meets testing in Erlang

-module(fib).-export([fib/1]).

fib(0) -> 1;fib(1) -> 2;fib(N) -> fib(N-1)+ fib(N-2).

Erlang example: Fibonacci

10th International Conference on Tests & Proofs

fib(0)1fib(1)1fib(2)2fib(3)3fib(4)5

…….

Page 18: Debugging meets testing in Erlang

-module(fib).-export([fib/1]).

fib(0) -> 1;fib(1) -> 2;fib(N) -> fib(N-1)+ fib(N-2).

Erlang example: Fibonacci

10th International Conference on Tests & Proofs

>fib(4)8

fib(0)1fib(1)1fib(2)2fib(3)3fib(4)5

…….

Page 19: Debugging meets testing in Erlang

-module(fib).-export([fib/1]).

fib(0) -> 1;fib(1) -> 2;fib(N) -> fib(N-1)+ fib(N-2).

Erlang example: Fibonacci

10th International Conference on Tests & Proofs

>fib(4)8>edd:dd(“fib(4)”)

!fib(0)1fib(1)1fib(2)2fib(3)3fib(4)5

…….

Page 20: Debugging meets testing in Erlang

-module(fib).-export([fib/1]).

fib(0) -> 1;fib(1) -> 2;fib(N) -> fib(N-1)+ fib(N-2).

Erlang example: Fibonacci

10th International Conference on Tests & Proofs

fib(4) -> 8

fib(1) -> 2

fib(2) -> 3

fib(2) -> 3

fib(3) -> 5

fib(1) -> 2

fib(1) -> 2

fib(0) -> 1

fib(0) -> 1

fib(0)1fib(1)1fib(2)2fib(3)3fib(4)5

…….

Page 21: Debugging meets testing in Erlang

-module(fib).-export([fib/1]).

fib(0) -> 1;fib(1) -> 2;fib(N) -> fib(N-1)+ fib(N-2).

Erlang example: Fibonacci

10th International Conference on Tests & Proofs

fib(4) -> 8

fib(1) -> 2

fib(2) -> 3 ?

fib(2) -> 3 ?

fib(3) -> 5

fib(1) -> 2

fib(1) -> 2

fib(0) -> 1

fib(0) -> 1

fib(0)1fib(1)1fib(2)2fib(3)3fib(4)5

…….

Invalid !

Page 22: Debugging meets testing in Erlang

-module(fib).-export([fib/1]).

fib(0) -> 1;fib(1) -> 2;fib(N) -> fib(N-1)+ fib(N-2).

Erlang example: Fibonacci

10th International Conference on Tests & Proofs

fib(4) -> 8

fib(1) -> 2 ?

fib(2) -> 3 ?

fib(2) -> 3 ?

fib(3) -> 5

fib(1) -> 2 ?

fib(1) -> 2 ?

fib(0) -> 1

fib(0) -> 1

fib(0)1fib(1)1fib(2)2fib(3)3fib(4)5

…….

Invalid !

Page 23: Debugging meets testing in Erlang

-module(fib).-export([fib/1]).

fib(0) -> 1;fib(1) -> 2;fib(N) -> fib(N-1)+ fib(N-2).

Erlang example: Fibonacci

10th International Conference on Tests & Proofs

fib(4) -> 8

fib(1) -> 2 ?

fib(2) -> 3

fib(2) -> 3

fib(3) -> 5

fib(1) -> 2 ?

fib(1) -> 2 ?

fib(0) -> 1

fib(0) -> 1

fib(0)1fib(1)1fib(2)2fib(3)3fib(4)5

…….

Buggy nodes !

Page 24: Debugging meets testing in Erlang

Motivation

24 10th International Conference on Tests & Proofs

Outline

Unit Testingin Erlang

Declarativedebugging

Page 25: Debugging meets testing in Erlang

Unit tests: Check units of code in (relative) isolation

Created by Kent Beck in 1998 (Sunit for Smalltalk)

xUnit, a big family: JUnit, Runit, NUnit

EUnit: Unit test framework for language Erlang

Unit Testing in Erlang

10th International Conference on Tests & Proofs

Page 26: Debugging meets testing in Erlang

Functional: functions as basic pieces of code

Concurrent: deals with thousands of processes readily

Dynamic Typing: variables declarated without types

Hot Swapping, single assignment, eager evaluation…

Erlang

Unit Testing in Erlang

10th International Conference on Tests & Proofs

Page 27: Debugging meets testing in Erlang

-module(quicksort).-export([qs/2, leq/2]).

qs(_, []) -> [];qs(F, [E|R]) -> {A, B} = partition(F, E, R), qs(F, B) ++ [E] ++ qs(F, A).

partition(_, _, []) -> {[], []};partition(F, E, [H|T]) ->

{A, B} = partition(F, E, T),case F(H, E) of

true -> {[H|A], B};false -> {A, B}

end.leq(A, B) -> A =< B.

Erlang example

10th International Conference on Tests & Proofs

Page 28: Debugging meets testing in Erlang

-include_lib("eunit/include/eunit.hrl").

quicksort_test() ->?assertEqual( qs(fun leq/2, []), []),?assertEqual( qs(fun leq/2, [1]), [1]),?assertEqual( qs(fun leq/2, [7,1]), [1,7]),?assertEqual( qs(fun leq/2, [7,8,1]), [1,7,8]).

Unit Testing in Erlang

Erlang EUnit example

quicksort:test(). ...*failed*in call from quicksort:quicksort_test/0

(quicksort.erl, line 22)**error:{assertEqual,[{module,quicksort},

{line,22},{expression,"[ 1 , 7 ]"},

10th International Conference on Tests & Proofs

Page 29: Debugging meets testing in Erlang

-include_lib("eunit/include/eunit.hrl").

quicksort_test() ->?assertEqual( qs(fun leq/2, []), []),?assertEqual( qs(fun leq/2, [1]), [1]),?assertEqual( qs(fun leq/2, [7,1]), [1,7]),?assertEqual( qs(fun leq/2, [7,8,1]), [1,7,8]).

Unit Testing in Erlang

Erlang EUnit example

quicksort:test(). ...*failed*in call from quicksort:quicksort_test/0

(quicksort.erl, line 22)**error:{assertEqual,[{module,quicksort},

{line,22},{expression,"[ 1 , 7 ]"},

10th International Conference on Tests & Proofs

Page 30: Debugging meets testing in Erlang

Motivation

30 10th International Conference on Tests & Proofs

Outline

Unit Testingin Erlang

Declarativedebugging

Our proposal

Page 31: Debugging meets testing in Erlang

Debugging meets testing

> edd:dd("quicksort:qs( fun quicksort:leq/2, [7,1] )").

qs(fun leq/2, [7, 1]) = [7, 1]

qs(fun leq/2, [1]) = [1] qs(fun leq/2, []) = [] partition(fun leq/2, 7, [1]) = {[1], []}

leq(1,7) = true

partition(fun leq/2, 7, []) = {[], []}qs(fun leq/2, []) = []partition(fun leq/2, 1, []) = {[], []}

10th International Conference on Tests & Proofs

Page 32: Debugging meets testing in Erlang

Debugging meets testing

> edd:dd("quicksort:qs( fun quicksort:leq/2, [7,1] )").

qs(fun leq/2, [7, 1]) = [7, 1]

qs(fun leq/2, [1]) = [1] qs(fun leq/2, []) = [] partition(fun leq/2, 7, [1]) = {[1], []}

leq(1,7) = true

partition(fun leq/2, 7, []) = {[], []}qs(fun leq/2, []) = []partition(fun leq/2, 1, []) = {[], []}

?assertEqual( qs(fun leq/2, []), [])

10th International Conference on Tests & Proofs

Page 33: Debugging meets testing in Erlang

Debugging meets testing

> edd:dd("quicksort:qs( fun quicksort:leq/2, [7,1] )").

qs(fun leq/2, [7, 1]) = [7, 1]

qs(fun leq/2, [1]) = [1] partition(fun leq/2, 7, [1]) = {[1], []}

leq(1,7) = true

partition(fun leq/2, 7, []) = {[], []}partition(fun leq/2, 1, []) = {[], []}

10th International Conference on Tests & Proofs

Page 34: Debugging meets testing in Erlang

Debugging meets testing

> edd:dd("quicksort:qs( fun quicksort:leq/2, [7,1] )").

qs(fun leq/2, [7, 1]) = [7, 1]

qs(fun leq/2, [1]) = [1] partition(fun leq/2, 7, [1]) = {[1], []}

leq(1,7) = true

partition(fun leq/2, 7, []) = {[], []}partition(fun leq/2, 1, []) = {[], []}

?assertEqual( qs(fun leq/2, [1]), [1])

10th International Conference on Tests & Proofs

Page 35: Debugging meets testing in Erlang

Debugging meets testing

> edd:dd("quicksort:qs( fun quicksort:leq/2, [7,1] )").

8 .- qs(fun leq/2, [7, 1]) = [7, 1]

2 .- partition(fun leq/2, 7, [1]) = {[1], []}

1 .- leq(1,7) = true

0 .- partition(fun leq/2, 7, []) = {[], []}

?assertEqual( qs(fun leq/2, [7,1]), [1,7]),

10th International Conference on Tests & Proofs

Page 36: Debugging meets testing in Erlang

Debugging meets testing

> edd:dd("quicksort:qs( fun quicksort:leq/2, [7,1] )").

qs(fun leq/2, [7, 1]) = [7, 1]

partition(fun leq/2, 7, [1]) = {[1], []}

leq(1,7) = true

partition(fun leq/2, 7, []) = {[], []}

> partition(fun quicksort:leq/2, 7, [1]) = {[1], []}?

10th International Conference on Tests & Proofs

Page 37: Debugging meets testing in Erlang

Debugging meets testing

> edd:dd("quicksort:qs( fun quicksort:leq/2, [7,1] )").

qs(fun leq/2, [7, 1]) = [7, 1]

partition(fun leq/2, 7, [1]) = {[1], []}

leq(1,7) = true

partition(fun leq/2, 7, []) = {[], []}

> partition(fun quicksort:leq/2, 7, [1]) = {[1], []}? y

10th International Conference on Tests & Proofs

Page 38: Debugging meets testing in Erlang

Testing meets debugging

> edd:dd("quicksort:qs( fun quicksort:leq/2, [7,1] )").

qs(fun leq/2, [7, 1]) = [7, 1]

partition(fun leq/2, 7, [1]) = {[1], []}

leq(1,7) = true

partition(fun leq/2, 7, []) = {[], []}

> partition(fun quicksort:leq/2, 7, [1]) = {[1], []}? y

quicksort_test() ->?assertEqual( qs(fun leq/2, []), []),?assertEqual( qs(fun leq/2, [1]), [1]),?assertEqual( qs(fun leq/2, [7,1]), [1,7]),?assertEqual( qs(fun leq/2, [7,8,1]), [1,7,8])?assertEqual( partition(fun leq/2, 7, [1] ), {[1], [ ]} )

10th International Conference on Tests & Proofs

Page 39: Debugging meets testing in Erlang

Debugging meets testing

> edd:dd("quicksort:qs( fun quicksort:leq/2, [7,1] )").

qs(fun leq/2, [7, 1]) = [7, 1]

error: quicksort:qs(fun quicksort:leq/2, [7, 1]) = [7, 1]Please, revise the second clause:qs(F, [E | R]) -> {A, B} = partition(F, E, R), qs(F, B) ++ [E] ++ qs(F, A).

10th International Conference on Tests & Proofs

Page 40: Debugging meets testing in Erlang

-module(quicksort).-export([qs/2, leq/2]).

qs(_, []) -> [];qs(F, [E|R]) -> {A, B} = partition(F, E, R), qs(F, A) ++ [E] ++ qs(F, B).

partition(_, _, []) -> {[], []};partition(F, E, [H|T]) ->

{A, B} = partition(F, E, T),case F(H, E) of

true -> {[H|A], B};false -> {A, B}

end.leq(A, B) -> A =< B.

Erlang example

10th International Conference on Tests & Proofs

Page 41: Debugging meets testing in Erlang

Testing meets debugging

Another test case failing!!! another error

quicksort:test(). ...*failed*in call from quicksort:quicksort_test/0 (quicksort.erl, line 23)**error:{assertEqual,[{module,quicksort},

{line,23},{expression,"[ 1 , 7 , 8 ]"},{expected,[1,7]},{value,[1,7,8]}]}

After correcting the error we try again the tests

10th International Conference on Tests & Proofs

Page 42: Debugging meets testing in Erlang

Testing meets debugging

> edd:dd("quicksort:qs( fun quicksort:leq/2, [7,8,1] )").

qs(fun leq/2, [7, 8, 1]) = [1, 7]

qs(fun leq/2, [1]) = [1] qs(fun leq/2, []) = [] partition(fun leq/2, 7, [8,1]) = {[1], []}

leq(8,7) = false

partition(fun leq/2, 7, [1]) = {[1], []}qs(fun leq/2, []) = []partition(fun leq/2, 1, []) = {[], []}

leq(1,7) = true partition(fun leq/2, 7, [0]) = {[], []}

10th International Conference on Tests & Proofs

Page 43: Debugging meets testing in Erlang

Testing meets debugging

> edd:dd("quicksort:qs( fun quicksort:leq/2, [7,8,1] )").

qs(fun leq/2, [7, 8, 1]) = [1, 7]

qs(fun leq/2, [1]) = [1] qs(fun leq/2, []) = [] partition(fun leq/2, 7, [8,1]) = {[1], []}

leq(8,7) = false

partition(fun leq/2, 7, [1]) = {[1], []}qs(fun leq/2, []) = []partition(fun leq/2, 1, []) = {[], []}

leq(1,7) = true partition(fun leq/2, 7, [0]) = {[], []}

?assertEqual( qs(fun leq/2, []), []),?assertEqual( qs(fun leq/2, [1]), [1]),?assertEqual( qs(fun leq/2, [7,1]), [1,7]),?assertEqual( qs(fun leq/2, [7,8,1]), [1,7,8])?assertEqual( partition(fun leq/2, 7, [1] ), {[1], [ ]} ).

10th International Conference on Tests & Proofs

Page 44: Debugging meets testing in Erlang

Testing meets debugging

> edd:dd("quicksort:qs( fun quicksort:leq/2, [7,8,1] )").

qs(fun leq/2, [7, 8, 1]) = [1, 7]

partition(fun leq/2, 7, [8,1]) = {[1], []}

leq(8,7) = false

partition(fun leq/2, 7, [8, 1]) = {[1], []}?

Debugging session

10th International Conference on Tests & Proofs

Page 45: Debugging meets testing in Erlang

Testing meets debugging

> edd:dd("quicksort:qs( fun quicksort:leq/2, [7,8,1] )").

qs(fun leq/2, [7, 8, 1]) = [1, 7]

partition(fun leq/2, 7, [8,1]) = {[1], []}

leq(8,7) = false

partition(fun leq/2, 7, [8, 1]) = {[1], []}?

Debugging session

v

Meaning: “this is wrong, and I know theexpected value”

10th International Conference on Tests & Proofs

Page 46: Debugging meets testing in Erlang

Testing meets debugging

> edd:dd("quicksort:qs( fun quicksort:leq/2, [7,8,1] )").

qs(fun leq/2, [7, 8, 1]) = [1, 7]

partition(fun leq/2, 7, [8,1]) = {[1], []}

leq(8,7) = false

partition(fun leq/2, 7, [8, 1]) = {[1], []}? vWhat is the value you expected? {[1],[8]}

A new positive test case is generated!

10th International Conference on Tests & Proofs

Page 47: Debugging meets testing in Erlang

Testing meets debugging

> edd:dd("quicksort:qs( fun quicksort:leq/2, [7,8,1] )").

qs(fun leq/2, [7, 8, 1]) = [1, 7]

partition(fun leq/2, 7, [8,1]) = {[1], []}

leq(8,7) = false

partition(fun leq/2, 7, [8, 1]) = {[1], []}? vWhat is the value you expected? {[1],[8]}leq(8, 7) = false? t

10th International Conference on Tests & Proofs

“I trust this function, mark all thequestions about leq as valid”

Page 48: Debugging meets testing in Erlang

Testing meets debugging

> edd:dd("quicksort:qs( fun quicksort:leq/2, [7,8,1] )").

qs(fun leq/2, [7, 8, 1]) = [1, 7]

partition(fun leq/2, 7, [8,1]) = {[1], []}

leq(8,7) = false

partition(fun leq/2, 7, [8, 1]) = {[1], []}? vWhat is the value you expected? {[1],[8]}leq(8, 7) = false? t

10th International Conference on Tests & Proofs

2 new assertions / test cases!

Page 49: Debugging meets testing in Erlang

Testing meets debugging

> edd:dd("quicksort:qs( fun quicksort:leq/2, [7,8,1] )").

qs(fun leq/2, [7, 8, 1]) = [1, 7]

partition(fun leq/2, 7, [8,1]) = {[1], []}

leq(8,7) = false

Call to a function that contains an error:quicksort:partition(fun quicksort:leq/2, 7, [8, 1]) = {[1], []}Please, revise the second clausepartition(F, E, [H | T]) ->

{A, B} = partition(F, E, T),case F(H, E) oftrue -> {[H | A], B};false -> {A, B}

end.

Page 50: Debugging meets testing in Erlang

Testing meets debugging

> edd:dd("quicksort:qs( fun quicksort:leq/2, [7,8,1] )").

qs(fun leq/2, [7, 8, 1]) = [1, 7]

partition(fun leq/2, 7, [8,1]) = {[1], []}

leq(8,7) = false

Call to a function that contains an error:quicksort:partition(fun quicksort:leq/2, 7, [8, 1]) = {[1], []}Please, revise the second clausepartition(F, E, [H | T]) ->

{A, B} = partition(F, E, T),case F(H, E) oftrue -> {[H | A], B};false -> {A, [H | B]}

end.

Page 51: Debugging meets testing in Erlang

Testing meets debugging

No more bugs…at least in this talk (hopefully)

quicksort:test(). Test passed

After correcting the error we try again the tests

10th International Conference on Tests & Proofs

Page 52: Debugging meets testing in Erlang

Pros

Debugging becomes part of the software dev. life cycleNo need of initial tests they will be generated during debbuging

Cons

Only “deterministic” functions (for instance no input operations)The user answer really matter an erroneous answer becomes part of

the test suite

Pros and Cons

10th International Conference on Tests & Proofs

Page 53: Debugging meets testing in Erlang

Motivation

53 10th International Conference on Tests & Proofs

Outline

Unit Testingin Erlang

Declarativedebugging

Our proposal Conclusions

Page 54: Debugging meets testing in Erlang

Debugging: A lot of useful information thrown away

Declarative debugging: store the information as Unit Tests

Unit Testing: saves questions in declarative debugging

General approach: presented for Erlang but can be seen as a general result

Conclusions

10th International Conference on Tests & Proofs

Page 55: Debugging meets testing in Erlang

Thanks for your attention