Pairwise and property based testing

Post on 20-Feb-2017

324 views 0 download

transcript

Pairwise & Property-Based TestingAgustín Ramos

@MachinesAreUs

1 / 37

Así que ya te decidiste a hacer pruebasautomatizadas...

Unitarias

De integración

De aceptación / funcionales

De desempeño

Solo tengo algo que decir...

2 / 37

Yarrrr so cool!3 / 37

Ya te vi

4 / 37

Algún día...

5 / 37

Tú...6 / 37

¿Qué dificultades te has encontrado alimplementar pruebas?

Toma su tiempo

Requiere el uso de varios frameworks y técnicas

Aumenta la cantidad de código a escribir *

Hace que el 'build' sea más lento

etc, etc...

7 / 37

¿Y qué pasa si no automatizas pruebas?Para probar una función/método:

Tengo que levantar toda la aplicación/ambiente

Tengo que seguir el flujo que me lleva a la llamada a mi función/método

Depende de las configuraciones de mi máquina

Ahora imagina... lo mismo para todas

las funciones del sistema

8 / 37

El problema del testing

9 / 37

Ejemplo 1¿Cuántos diferentes casos de prueba se necesitan para probar ésta interfaz?

10 / 37

Ejemplo 2¿Cuántos casos de prueba se necesitan para probar ésta función?

function partition(items, left, right) { var pivot = items[Math.floor((right + left) / 2)], i = left, j = right; while (i <= j) { while (items[i] < pivot) { i++; } while (items[j] > pivot) { j—; } if (i <= j) { swap(items, i, j); i++; j--; } } return i;}

Javascript Quicksort

11 / 37

Ejemplo 2¿Cuántos tipos de prueba se necesitan para probar ésta función?

function partition(items, left, right) { var pivot = items[Math.floor((right + left) / 2)], i = left, j = right; while (i <= j) { while (items[i] < pivot) { i++; } while (items[j] > pivot) { j—; } if (i <= j) { swap(items, i, j); i++; j--; } } return i;}

12 / 37

Ejemplo 2¿Cuántos tipos de prueba se necesitan para probar ésta función?

Valores en rangos esperados

Valores no esperados (Indices fuera de rango, nulos)

Condiciones de frontera (arreglo vacío, arreglo de tamaño máximo)

Valores que ejerciten las distintas rutas de ejecución

13 / 37

Ejemplo 2¿Cuántos rutas de ejecución tiene ésta función?

function partition(items, left, right) { var pivot = items[Math.floor((right + left) / 2)], i = left, j = right; while (i <= j) { while (items[i] < pivot) { i++; } while (items[j] > pivot) { j—; } if (i <= j) { swap(items, i, j); i++; j--; } } return i;}

14 / 37

Complejidad CiclomáticaMétrica.

Thomas J. McCabe, 1976

Mide el número de rutas de ejecución linealmente independientes dentro

de un programa.

Aproximador

2^N - 1

N es el número de bifurcaciones en el código (bloques if, where, for, etc.)

15 / 37

Ejemplo 2¿Cuántos rutas de ejecución tiene ésta función?

function partition(items, left, right) { var pivot = items[Math.floor((right + left) / 2)], i = left, j = right;* while (i <= j) {* while (items[i] < pivot) { i++; }* while (items[j] > pivot) { j—; }* if (i <= j) { swap(items, i, j); i++; j--; } } return i;}

2^4 = 16

Necesitas 16 distintos casos de prueba, solo para saber que pasaste por todaslas rutas de ejecución posibles

16 / 37

Ojo:

¿Por qué escribir código si no estás seguroque se debe ejecutar?

17 / 37

Corolario:

Entre menos código escribas y más sencillosea, es más fácil saber que funciona

18 / 37

El problema

es la explosión combinatorial

19 / 37

El PExC20 / 37

... y hay quienes además, quieren seguirhaciéndolo a mano.

21 / 37

Pairwise Testing

22 / 37

Pairwise TestingIdea central:

Es una técnica de generación de casos de prueba que se basa en laobservación de que la mayoría de los defectos (~90%) soncausados por interacciones de a lo más dos factores de prueba.

Con ésta técnica se generan todas las posibles combinaciones dedos valores distintos para cada factor de prueba y por tanto, lassuites de pruebas son mucho más pequeñas que las generadas demanera exhaustiva y aún así son muy efectivas para encontrardefectos.

23 / 37

EjemploTienes que probar un componente web que debe correr en distintos

navegadores (Chrome y Firefox), distintos sistemas operativos (OSX, Linux,Windows) y con diferentes capacidades de memoria de video (500Mb y 1Gb).

¿Cuántas posibles configuraciones tienes que probar?

Con pairwise testing son 6

Browser OS Video Memory

Chrome Windows 500Mb

Chrome Linux 1Gb

Chrome OSX 1Gb

Firefox Windows 1Gb

Firefox Linux 500Mb

Firefox OSX 500Mb

24 / 37

Pairwise testing vs Exhaustive testing

Pairwise Testing in the Real World

25 / 37

Property Based Testing

26 / 37

Property Based TestingEs una técnica complementaria a unit testing.

La idea es especificar un conjunto de propiedades que siempre se deben

cumplir (invariantes).

El framework (QuickCheck) genera un conjunto de ejemplos 'aleatorios'

contra los cuales probar si la propiedad se cumple o no.

Si encuentra un ejemplo que invalida la propiedad, trata de reducirlo a su

mínima expresión.

27 / 37

Quick Check - Ejemplo 1Vamos a verificar si una función que implementa el reverso de una cadenacumple ciertas propiedades.

Propiedad 1: El reverso del reverso de una cadena, es la misma cadena.

ghci> quickCheck (\s -> reverse(reverse s) == s)+++ OK, passed 100 tests.

Propiedad 2: El reverso de una cadena, tiene la misma longitud que la cadenaoriginal.

ghci> quickCheck (\s -> length(reverse s) == length s)+++ OK, passed 100 tests.

Propiedad 3: El reverso de una cadena palíndroma, es la misma cadena.

ghci> quickCheck (\s -> isPalindrome s ==> reverse s == s)+++ OK, passed 100 tests.

28 / 37

Quick Check - Ejemplo 2La siguiente máquina de estados acepta todas las cadenas cuyo número de 0es par.

La función 'decide' decide si el autómata acepta la cadena o no. Ejemplos:

decide "00100" == Truedecide "00110" == False

29 / 37

Quick Check - Ejemplo 2Propiedad 1: decide debe regresar solo True o False.

ghci> quickCheck (\s -> decide s ̀elem̀ [True, False])+++ OK, passed 100 tests.

Propiedad 2: decide sólo acepta cadenas con un númpero par de 0's.

ghci> quickCheck (\s -> isEvenZeros s == decide s)+++ OK, passed 100 tests.

Y... ¿si quiero probar 10,000 casos?

ghci> let deepCheck p = quickCheckWith (stdArgs {maxSuccess = 10000}) p

ghci> deepCheck (\s -> isEvenZeroes s == decide s) +++ OK, passed 10000 tests.

30 / 37

¿Y Java apá ?Mira mijo...

Hay varios frameworks

Ninguno me gusta

Pero da un vistazo a

Junit Theories

Quickcheck

Y si eres más atrevido, prueba ScalaCheck

31 / 37

JUnit Theories 1/2@Theorypublic void multiplyIsInverseOfDivideWithInlineDataPoints( @Between(first = -100, last = 100) int amount, @Between(first = -100, last = 100) int m) { assumeThat(m, not(0)); assertThat(new Dollar(amount).times(m).divideBy(m).getAmount(), is(amount));}

32 / 37

JUnit Theories 2/2@Retention(RetentionPolicy.RUNTIME)@ParametersSuppliedBy(BetweenSupplier.class)public @interface Between { int first();

int last();}

public static class BetweenSupplier extends ParameterSupplier { @Override public List getValues(Object test, ParameterSignature sig) { Between annotation = (Between) sig.getSupplierAnnotation();

ArrayList list = new ArrayList(); for (int i = annotation.first(); i <= annotation.last(); i++) list.add(i); return list; }}

33 / 37

¿Otros lenguajes?

¡Claro!

Google for it!!!

34 / 37

ResúmenHacer pruebas es difícil

Si no las haces... tabla

Si no las automatizas... tabla

Hacer buenas pruebas es aún más difícil

Si no estudias y te aplicas... tabla

¡pero no hay de otra!

Salvo vivir en la incertidumbre...

35 / 37

Más informaciónProperty Based Testing (video by @jessitron)

Pairwise testing (community website)

Combinatorial Software Testing (article)

Better than unit tests (article)

Practical Combinatorial Testing (NIST Report)

36 / 37

¡Happy Testing!Agustín Ramos

@MachinesAreUs

37 / 37