Pregunta

Me las he arreglado para obtener xUnit trabajando en mi montaje de muestra pequeño. Ahora quiero ver si puedo asimilar fscheck también. Mi problema es que estoy perplejo cuando se trata de definir las propiedades de prueba para mis funciones.

Tal vez he simplemente no dieron una buena muestra conjunto de funciones, pero lo que iba a ser buenas propiedades de ensayo de estas funciones, por ejemplo?

//transforms [1;2;3;4] into [(1,2);(3,4)]
pairs : 'a list -> ('a * 'a) list      //'

//splits list into list of lists when predicate returns 
//  true for adjacent elements
splitOn : ('a -> 'a -> bool) -> 'a list -> 'a list list

//returns true if snd is bigger
sndBigger : ('a * 'a) -> bool (requires comparison)

No hay solución correcta

Otros consejos

Ya hay un montón de respuestas específicas, así que trataremos de dar algunas respuestas generales que se podrían dar algunas ideas.

  1. propiedades inductivos para funciones recursivas. Para funciones simples, esto equivale probablemente para volver a la aplicación de la recursividad. Sin embargo, que sea sencillo: mientras que la ejecución real más a menudo que no evoluciona (por ejemplo, se convierte recursiva de cola, se agrega memoization, ...) mantienen la propiedad directa. El ==> combinador propiedad por lo general viene muy bien aquí. La función de sus pares podría ser un buen ejemplo.
  2. Las propiedades que posean más de varias funciones en un módulo o tipo. Este suele ser el caso cuando la comprobación tipos de datos abstractos. Por ejemplo: la adición de un elemento a un conjunto significa que la matriz contiene ese elemento. Esto comprueba la consistencia de Array.add y Array.contains.
  3. ida y vuelta: esto es bueno para las conversiones (por ejemplo, el análisis, la serialización) - generar una representación arbitraria, serializar, deserializar él, compruebe que es igual a la original. Usted puede ser capaz de hacer esto con splitOn y concat.
  4. Propiedades generales como comprobaciones de validez. Busque propiedades generalmente conocidos, que pueden encerrar - cosas como conmutatividad, asociatividad, idempotencia (aplicando algo dos veces, no cambia el resultado), la reflexividad, etc. La idea aquí es más de ejercer la función de un poco - ver si se hace algo realmente extraño .

Como una pieza general del consejo, trate de no hacer demasiado grande a un acuerdo fuera de él. Para sndBigger, una buena propiedad sería:

dejar que `` debe devolver verdadero si y sólo si es SND bigger`` (a: int) (b: int) =     sndBigger (a, b) = b> a

Y eso es probablemente exactamente la implementación. No se preocupe por ello - a veces un simple, prueba de la unidad pasada de moda es justo lo que necesita. Sin culpabilidad necesario! :)

este enlace (por el equipo de PEX) también da algunas ideas.

Voy a empezar con sndBigger - se trata de una función muy sencilla, pero se puede escribir algunas propiedades que debe contener al respecto. Por ejemplo, lo que ocurre cuando se invierte los valores de la tupla:

// Reversing values of the tuple negates the result
let swap (a, b) = (b, a)
let prop_sndBiggerSwap x = 
  sndBigger x = not (sndBigger (swap x))

// If two elements of the tuple are same, it should give 'false'
let prop_sndBiggerEq a = 
  sndBigger (a, a) = false

EDIT: Este prop_sndBiggerSwap regla no siempre (véase el comentario de kvb ). Sin embargo, el siguiente debe ser correcta:

// Reversing values of the tuple negates the result
let prop_sndBiggerSwap a b = 
  if a <> b then 
    let x = (a, b)
    sndBigger x = not (sndBigger (swap x))

En cuanto a la función pairs, kvb ya publicado algunas buenas ideas. Además, se puede comprobar que girando la lista transformado de nuevo en una lista de elementos devuelve la lista original (que necesita para tratar el caso en la lista de entrada es impar - dependiendo de lo que la función pairs debe hacer en este caso):

let prop_pairsEq (x:_ list) = 
  if (x.Length%2 = 0) then
    x |> pairs |> List.collect (fun (a, b) -> [a; b]) = x
  else true

Para splitOn, podemos probar algo similar - Si concatena todas las listas devueltas, se debe dar a la lista original (esto no verifica el comportamiento de división, pero es una buena cosa para empezar con - al menos garantías que no se perderán los elementos).

let prop_splitOnEq f x = 
  x |> splitOn f |> List.concat = x

No estoy seguro de si fscheck puede manejar esto, sin embargo (!) Porque la propiedad tiene una función como argumento (por lo que necesitaría generar "funciones aleatorias"). Si esto no funciona, tendrá que proporcionar un par de propiedades más específicas con un poco de f función manuscrita. A continuación, la aplicación de la verificación de que f devuelve verdadero para todos los pares adyacentes de las listas splitted (como kvb indica) en realidad no es tan difícil:

let prop_splitOnAdjacentTrue f x = 
  x |> splitOn f 
    |> List.forall (fun l -> 
         l |> Seq.pairwise 
           |> Seq.forall (fun (a, b) -> f a b))

Probablemente la única cosa pasada que se puede comprobar es que f vuelve false cuando le das el último elemento de una lista y el primer elemento de la lista siguiente. Lo siguiente no es totalmente completa, sino que muestra el camino a seguir:

let prop_splitOnOtherFalse f x = 
  x |> splitOn f
    |> Seq.pairwise 
    |> Seq.forall (fun (a, b) -> lastElement a = firstElement b)

El último ejemplo también muestra que usted debe comprobar si la función splitOn puede devolver una lista vacía como parte de la lista devuelta de los resultados (ya que en ese caso, no se podía encontrar primero / último elemento).

Por cierto código (por ejemplo sndBigger), la aplicación es tan simple que cualquier propiedad será al menos tan complejo como el código original, por lo que las pruebas a través de fscheck puede no tener sentido. Sin embargo, para las otras dos funciones aquí hay algunas cosas que se puede consultar:

  • pairs
    • ¿Qué se espera cuando la longitud original no es divisible por dos? Usted puede comprobar para lanzar una excepción si ese es el comportamiento correcto.
    • List.map fst (pairs x) = evenEntries x y List.map snd (pairs x) = oddEntries x para funciones simples y evenEntries oddEntries que se puede escribir.
  • splitOn
    • Si entiendo su descripción de cómo se supone que la función de trabajar, a continuación, se puede comprobar las condiciones como "Por cada lista en el resultado de splitOn f l, no hay dos entradas consecutivas satisfacen f" y "listas que tienen (l1,l2) de pares splitOn f l, f (last l1) (first l2) sostiene". Por desgracia, la lógica aquí será probablemente comparable en complejidad a la aplicación en sí.
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top