Be#er ¡Tes(ng ¡with ¡Less ¡Work: ¡ QuickCheck ¡Tes(ng ¡in ¡Prac(ce ¡
John ¡Hughes ¡
Be#er Tes(ng with Less Work: QuickCheck Tes(ng in Prac(ce - - PowerPoint PPT Presentation
Be#er Tes(ng with Less Work: QuickCheck Tes(ng in Prac(ce John Hughes QuickCheck in a Nutshell Test case Test case Test case Proper(es Test
John ¡Hughes ¡
Proper(es ¡
Test ¡case ¡ Test ¡case ¡ Test ¡case ¡ Test ¡case ¡ Test ¡case ¡ Minimal Test ¡case ¡
– One ¡property ¡replaces ¡many ¡tests ¡
– Lots ¡of ¡combina(ons ¡you’d ¡never ¡test ¡by ¡hand ¡
– Failures ¡minimized ¡automagically ¡
base64_encode(Config) when is_list(Config) -> %% Two pads <<"QWxhZGRpbjpvcGVuIHNlc2FtZQ==">> = base64:encode("Aladdin:open sesame"), %% One pad <<"SGVsbG8gV29ybGQ=">> = base64:encode(<<"Hello World">>), %% No pad "QWxhZGRpbjpvcGVuIHNlc2Ft" = base64:encode_to_string("Aladdin:open sesam"), "MDEyMzQ1Njc4OSFAIzBeJiooKTs6PD4sLiBbXXt9" = base64:encode_to_string( <<"0123456789!@#0^&*();:<>,. []{}">>),
Test ¡cases ¡ Expected ¡results ¡
prop_base64() -> ?FORALL(Data,list(choose(0,255)), base64:encode(Data)==???).
base64_encode(Config) when is_list(Config) -> %% Two pads <<"QWxhZGRpbjpvcGVuIHNlc2FtZQ==">> = base64:encode("Aladdin:open sesame"), %% One pad <<"SGVsbG8gV29ybGQ=">> = base64:encode(<<"Hello World">>), %% No pad "QWxhZGRpbjpvcGVuIHNlc2Ft" = base64:encode_to_string("Aladdin:open sesam"), "MDEyMzQ1Njc4OSFAIzBeJiooKTs6PD4sLiBbXXt9" = base64:encode_to_string( <<"0123456789!@#0^&*();:<>,. []{}">>),
Where ¡did ¡ these ¡come ¡ from? ¡
– Only ¡tests ¡that ¡changes ¡don’t ¡affect ¡the ¡result, ¡not ¡ that ¡the ¡result ¡is ¡right ¡ Use ¡the ¡other ¡ encoder ¡as ¡an ¡
Use ¡an ¡old ¡ version ¡(or ¡a ¡ simpler ¡version) ¡ as ¡an ¡oracle ¡
What ¡does ¡this ¡test? ¡
consistent ¡misunderstanding ¡of ¡base64 ¡
Simple ¡proper6es ¡find ¡a ¡lot ¡of ¡bugs! ¡
prop_encode_decode() -> ?FORALL(L,list(choose(0,255)), base64:decode(base64:encode(L)) == list_to_binary(L)).
ingenuity… ¡
effec(ve! ¡
thing ¡is ¡o"en ¡powerful! ¡
API ¡ Calls ¡ API ¡ Calls ¡ API ¡ Calls ¡ API ¡ Calls ¡
Model ¡ state ¡ Model ¡ state ¡ Model ¡ state ¡ Model ¡ state ¡
postcondi6ons ¡
put ¡ 2 ¡ get ¡ put ¡ 3 ¡ get ¡ put ¡ 1 ¡
[1] ¡
[1,2] ¡
[2] ¡
[2,3] ¡
[] ¡
1 ¡ 2 ¡
Use ¡an ¡Erlang ¡list ¡to ¡model ¡the ¡contents ¡of ¡the ¡queue! ¡
next_state_data(_,_,S,_,{call,_,put,[_,X]}) ¡-‑> ¡ ¡ ¡ ¡ ¡S#state{elements=S#state.elements++[X]}; ¡ next_state_data(_,_,S,_,{call,_,get,_}) ¡-‑> ¡ ¡ ¡ ¡ ¡S#state{elements=tl(S#state.elements)}; ¡ postcondi(on(_,_,S,{call,_,get,_},Res) ¡-‑> ¡ ¡ ¡ ¡ ¡Res ¡== ¡hd(S#state.elements); ¡ postcondi(on(_,_,S,{call,_,size,_},Res) ¡-‑> ¡ ¡ ¡ ¡ ¡Res ¡== ¡length(S#state.elements); ¡
prop_q() -> ?FORALL(Cmds,commands(?MODULE), begin {H,S,Res} = run_commands(?MODULE,Cmds), Res == ok) end).
Mentor ¡Graphics ¡
AutoSAR ¡clusters ¡ ¡
– Com, ¡PDUR, ¡CAN, ¡FlexRay, ¡Lin, ¡DEM… ¡
– test ¡code ¡10x ¡smaller ¡than ¡implementa(on ¡ – 20x ¡smaller ¡than ¡the ¡standard! ¡
– And ¡in ¡the ¡standard… ¡
"We ¡know ¡there ¡is ¡a ¡lurking ¡bug ¡somewhere ¡ in ¡the ¡dets ¡code. ¡We ¡have ¡got ¡'bad ¡object' ¡ and ¡'premature ¡eof' ¡every ¡other ¡month ¡the ¡ last ¡year. ¡We ¡have ¡not ¡been ¡able ¡to ¡track ¡the ¡ bug ¡down ¡since ¡the ¡dets ¡files ¡is ¡repaired ¡ automa(cally ¡next ¡(me ¡it ¡is ¡opened.“ ¡ Tobbe ¡Törnqvist, ¡Klarna, ¡2007 ¡
Applica(on ¡ Mnesia ¡ Dets ¡ File ¡system ¡
Invoicing ¡services ¡for ¡web ¡shops ¡ Distributed ¡database: ¡ transac(ons, ¡distribu(on, ¡ replica(on ¡ Tuple ¡storage ¡ 500+ ¡ people ¡in ¡ 5 ¡years ¡ Race ¡ condi(ons? ¡
dispenser:take_(cket() ¡ dispenser:reset() ¡
1 = 2 = 3 =
1 =
test_dispenser() -> Expected ¡ results ¡
BUT… ¡
reset(), take_ticket(), take_ticket(), take_ticket(), reset(), take_ticket().
reset ¡ take_(cket ¡ take_(cket ¡ take_(cket ¡ 1 ¡ 2 ¡ 3 ¡ 1 ¡ 3 ¡ 2 ¡ 1 ¡ 2 ¡ 1 ¡
reset ¡ take_(cket ¡ take_(cket ¡ take_(cket ¡ take_(cket ¡ reset ¡
reset ¡
take ¡ take ¡ take ¡ 0 ¡ 0 ¡ 1 ¡ 2 ¡
reset ok ¡
take 1 ¡ take 3 ¡ take 2 ¡ 0 ¡ 0 ¡ 1 ¡ 2 ¡
prop_parallel() -> ?FORALL(Cmds,parallel_commands(?MODULE), begin start(), {H,Par,Res} = run_parallel_commands(?MODULE,Cmds), Res == ok) end)).
Generate ¡parallel ¡ test ¡cases ¡ Run ¡tests, ¡check ¡for ¡a ¡ matching ¡serializa(on ¡
Prefix: ¡ Parallel: ¡
Result: ¡no_possible_interleaving ¡ take_(cket() ¡-‑> ¡ ¡ ¡ ¡ ¡N ¡= ¡read(), ¡ ¡ ¡ ¡ ¡write(N+1), ¡ ¡ ¡ ¡ ¡N+1. ¡
¡{Key, ¡Value1, ¡Value2…} ¡
– insert(Table,ListOfTuples) ¡ – delete(Table,Key) ¡ – insert_new(Table,ListOfTuples) ¡ – … ¡
– List ¡of ¡tuples ¡(almost) ¡
> ¡6,000 ¡ LOC ¡
Prefix:
dets_table Parallel:
Result: no_possible_interleaving
insert_new(Name, ¡Objects) ¡-‑> ¡Bool ¡ Types: ¡ Name ¡= ¡name() ¡ Objects ¡= ¡object() ¡| ¡[object()] ¡ Bool ¡= ¡bool() ¡
Prefix:
Parallel:
=ERROR ¡REPORT==== ¡4-‑Oct-‑2010::17:08:21 ¡=== ¡ ** ¡dets: ¡Bug ¡was ¡found ¡when ¡accessing ¡table ¡dets_table ¡
Prefix:
Parallel:
get_contents(dets_table) --> [] Result: no_possible_interleaving
Dets ¡ server ¡ Reordering ¡and ¡ concurrency! ¡
Prefix:
close(dets_table) --> ok
Parallel:
Result: ok
premature ¡eof ¡
Prefix:
insert(dets_table,[{1,0}]) --> ok Parallel:
delete(dets_table,1) --> ok
Result: ok false
bad ¡object ¡
"We ¡know ¡there ¡is ¡a ¡lurking ¡bug ¡somewhere ¡ in ¡the ¡dets ¡code. ¡We ¡have ¡got ¡'bad ¡object' ¡ and ¡'premature ¡eof' ¡every ¡other ¡month ¡the ¡ last ¡year.” ¡ Tobbe ¡Törnqvist, ¡Klarna, ¡2007 ¡ Each ¡bug ¡fixed ¡the ¡day ¡aqer ¡ repor(ng ¡the ¡failing ¡case ¡
– Mature ¡produc(on ¡code ¡ – >6 ¡weeks ¡of ¡work ¡ – …files ¡of ¡over ¡4GB? ¡ – …rehashing ¡could ¡be ¡the ¡problem? ¡ – Diagnosing ¡races ¡in ¡produc(on ¡is ¡hopeless ¡
– Unit ¡tests ¡for ¡races ¡are ¡hard ¡to ¡write… ¡ – …so ¡people ¡don’t! ¡ – Races=feature ¡interac(on ¡ ¡imprac(cally ¡many ¡tests ¡
– Understanding ¡and ¡genera(ng ¡test ¡inputs ¡
– New ¡code ¡is ¡buggy ¡ – Misunderstandings ¡of ¡the ¡informal ¡spec ¡ – Undocumented ¡features ¡of ¡the ¡system ¡ – Undocumented ¡limitaAons ¡of ¡the ¡system ¡
every ¡run ¡
– There ¡is ¡a ¡”most ¡likely ¡bug” ¡ – Other ¡bugs ¡usually ¡shrink ¡to ¡the ¡most ¡likely ¡one ¡
excluded ¡
– Bug ¡precondiAons ¡document ¡the ¡limita(ons ¡of ¡the ¡ system ¡
accounted ¡for, ¡real ¡bugs ¡start ¡to ¡appear ¡
improvement ¡in ¡the ¡variety ¡of ¡tests ¡