2012-05-17 24 views
7

He creado una Teoría NUnit para ayudarme a probar algún código. El código real que se prueba no es tan importante para esta pregunta como los datos que estoy usando para probarlo. A saber, las horas y los minutos de tiempo en un reloj de 24 horas.¿Cómo diseñar una teoría NUnit?

Escribí mi dispositivo de esta manera para capitalizar las características y cumplir con las limitaciones dentro de la función de teoría NUnit 2.6. En particular, sentí que tenía que crear clases, como Hora y Minuto, para evitar la característica de que los Puntos de datos coinciden con los argumentos por tipo exacto.

[TestFixture] 
public class TimeWindowParserTheoryFixture 
{ 
    public class Hour 
    { 
     public int Value; 
    } 

    public class Minute 
    { 
     public int Value; 
     public string AsString { get { return Value.ToString("00"); } } 
    } 

    [Datapoints] 
    public IEnumerable<Hour> Hours 
    { 
     get 
     { 
      return Enumerable 
       .Range(0, 25) 
       .Select(v => new Hour() { Value = v }) 
       .Union(Enumerable.Repeat((Hour)null, 1)); 
     } 
    } 

    [Datapoints] 
    public IEnumerable<Minute> Minutes 
    { 
     get 
     { 
      return Enumerable 
       .Range(0, 60) 
       .Select(v => new Minute() { Value = v }) 
       .Union(Enumerable.Repeat((Minute)null, 1)); 
     } 
    } 

    [Datapoints] 
    public IEnumerable<string> Separators 
    { 
     get { return new[] { " ", "-" }; } 
    } 

    [Theory] 
    public void ValidHours(Hour startHour, 
     Minute startMinute, 
     Hour endHour, 
     Minute endMinute, 
     string separator) 
    { 
     Assume.That(startHour != null); 
     Assume.That(endHour != null); 

     var parser = new TimeWindowParser(); 
     var startMinutesString = String.Format("{0}{1}", startMinute == null ? "" : ":", startMinute == null ? "" : startMinute.AsString); 
     var endMinutesString = String.Format("{0}{1}", endMinute == null ? "" : ":", endMinute == null ? "" : endMinute.AsString); 
     var pattern = String.Format("{0}{1}{2}{3}{4}{5}{6}", startHour, startMinutesString, "", separator, endHour, endMinutesString, ""); 
     //Console.WriteLine(pattern); 
     var result = parser.Parse(pattern); 
     Assert.That(result, Is.Not.Null); 
     Assert.That(result.Start, Is.EqualTo(startHour)); 
     Assert.That(result.End, Is.EqualTo(endHour)); 
    } 
} 

Lo que encontré es que el tamaño del conjunto de datos producidos durante la lógica combinatoria predeterminado de resultados de NUnit en un conjunto tan grande que me quede sin memoria. No parece que haya sido un problema la forma en que configuré la prueba y los datos, pero dado que obviamente es así, estoy pidiendo consejos sobre cómo pensar sobre este problema de manera diferente. Aquí está el rastro de la pila OutOfMemoryException que obtengo.

System.OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown. 
at System.Text.StringBuilder.ExpandByABlock(Int32 minBlockCharCount) 
at System.Text.StringBuilder.Append(Char* value, Int32 valueCount) 
at System.Text.StringBuilder.AppendHelper(String value) 
at System.Text.StringBuilder.Append(String value) 
at NUnit.Core.MethodHelper.GetDisplayName(MethodInfo method, Object[] arglist) 
at NUnit.Core.Builders.NUnitTestCaseBuilder.BuildSingleTestMethod(MethodInfo method, Test parentSuite, ParameterSet parms) 

Esta excepción es impar en sí mismo, ya que parece ser generada simplemente tratando de obtener el nombre del método de prueba (vea GetDisplayName). No estoy seguro si esto es un error (conocido o no). Por cierto, obtengo una excepción OOM muy similar cuando reescribí este dispositivo utilizando los atributos Range y Value menos experimentales utilizados en las pruebas parametrizadas.

Respuesta

10

Su pregunta es acerca de la mecánica del uso de las teorías, pero quiero hablar primero sobre la "teoría de las teorías", luego volveré a los detalles de implementación.

teoría de las teorías

Sólo se debe utilizar una teoría si usted tiene una teoría para comenzar. De lo contrario, solo está utilizando puntos de datos para impulsar las pruebas tradicionales basadas en ejemplos. Al "tener una teoría" me refiero a tener una declaración general de la verdad, que desea probar sobre un conjunto de entradas. Generalmente, la Teoría (código) revisará las posibles entradas y filtrará cualquier cosa que no cumpla con sus suposiciones. Un ejemplo de una buena teoría es: para cualquier número real positivo, la raíz cuadrada multiplicada por sí misma dará el mismo número. "

Mirando su prueba, no puedo entender qué teoría está tratando de demostrar su teoría Parece una prueba parametrizada estándar, con la excepción de que está utilizando DataPoints. La única suposición que debe hacer es que los minuts no son nulos, lo que es extraño ya que proporciona los minutos en primer lugar.

en pocas palabras: no creo que este es un buen uso de la Teoría

MECANICA

. Está generando 24 * 24 * 60 * 60 * 2 DataPoints. Esa es una gran cantidad de datos. ¿Tiene alguna razón para creer que su algoritmo de análisis podría funcionar, por ejemplo, 24:13 pero fallar durante 24:14?

Es cierto que los puntos de datos se usan combinatoriamente y podría ser mejor si se usaran por pares. Pero recuerde que los DataPoints son solo una de las muchas maneras de arrojar datos a una Teoría. La idea es que las Teorías deben manejar cualquier dato que les des.

ALTERNATIVA

que iba a escribir esto como una prueba, ya que no puedo pensar en ninguna teoría acerca de su analizador o analizadores en general que se aplicaría. Solo daría datos válidos a la prueba, probablemente usando TestCaseSourceAttribute apuntando a un método que genera cadenas válidas o simplemente a una gran variedad de cadenas.Tendría otra prueba que maneja varios tipos de datos no válidos.

Charlie