Creación de una prueba unitaria controlada por datos

Puede usar el marco de pruebas unitarias de Microsoft (MSTest) para código administrado a fin de configurar un método de prueba unitaria para recuperar valores de un origen de datos. El método se ejecuta correctamente para cada fila del origen de datos, lo que facilita probar una variedad de entrada mediante el uso de un único método.

Una prueba unitaria controlada por datos puede usar cualquiera de las variantes siguientes:

  • datos insertados con el atributo DataRow
  • datos de miembro con el atributo DynamicData
  • de algún proveedor de origen conocido con el atributo DataSource

Método sometido a prueba

Por ejemplo, supongamos que ha creado:

  1. Una solución denominada MyBank que acepta y procesa las transacciones para diferentes tipos de cuentas.

  2. Un proyecto en MyBank llamado BankDb que administra las transacciones para las cuentas.

  3. Una clase denominada Maths en el BankDb proyecto que realiza las funciones matemáticas para asegurarse de que cualquier transacción es una ventaja para el banco.

  4. Un proyecto de prueba unitaria denominado BankDbTests para probar el comportamiento del componente BankDb.

  5. Una clase unitaria de denominada MathsTests para probar el comportamiento de la clase Maths.

Probaremos un método en Maths que agrega dos enteros mediante un bucle:

public int AddIntegers(int first, int second)
{
    int sum = first;
    for (int i = 0; i < second; i++)
    {
        sum += 1;
    }

    return sum;
}

Probar el método de prueba

Prueba controlada por datos insertada

Para las pruebas insertadas, MSTest usa DataRow para especificar los valores que usa la prueba controlada por datos. La prueba de este ejemplo se ejecuta sucesivamente para cada fila de datos.

[TestMethod]
[DataRow(1, 1, 2)]
[DataRow(2, 2, 4)]
[DataRow(3, 3, 6)]
[DataRow(0, 0, 1)] // The test run with this row fails
public void AddIntegers_FromDataRowTest(int x, int y, int expected)
{
    var target = new Maths();
    int actual = target.AddIntegers(x, y);
    Assert.AreEqual(expected, actual,
        "x:<{0}> y:<{1}>",
        new object[] {x, y});
}

Prueba controlada por datos de un miembro

MSTest usa el atributo DynamicData para especificar el nombre, la variante (propiedad, valor predeterminado o método) y el tipo de definición (de forma predeterminada se usa el tipo actual) del miembro que proporcionará los datos que usa la prueba controlada por datos.

public static IEnumerable<object[]> AdditionData
{
    get
    {
        return new[]
        { 
            new object[] { 1, 1, 2 },
            new object[] { 2, 2, 4 },
            new object[] { 3, 3, 6 },
            new object[] { 0, 0, 1 }, // The test run with this row fails
        };
    }
}

[TestMethod]
[DynamicData(nameof(AdditionData))]
public void AddIntegers_FromDynamicDataTest(int x, int y, int expected)
{
    var target = new Maths();
    int actual = target.AddIntegers(x, y);
    Assert.AreEqual(expected, actual,
        "x:<{0}> y:<{1}>",
        new object[] {x, y});
}

También se puede reemplazar el nombre para mostrar generado de forma predeterminada mediante la propiedad DynamicDataDisplayName del atributo DynamicData. La signatura de método del nombre para mostrar debe ser public static string y aceptar dos parámetros, el primero de tipo MethodInfo y el segundo de tipo object[].

public static string GetCustomDynamicDataDisplayName(MethodInfo methodInfo, object[] data)
{
    return string.Format("DynamicDataTestMethod {0} with {1} parameters", methodInfo.Name, data.Length);
}

[DynamicData(nameof(AdditionData), DynamicDataDisplayName = nameof(GetCustomDynamicDataDisplayName))]

Prueba controlada por datos del proveedor de origen

Crear una prueba unitaria controlada por el origen de datos implica los pasos siguientes:

  1. Crear un origen de datos que contiene los valores que se utilizan en el método de prueba. El origen de datos puede ser cualquier tipo que está registrado en el equipo que ejecuta la prueba.

  2. Agregue una propiedad TestContext pública de tipo TestContext a la clase de prueba.

  3. Cree un método de prueba unitaria.

  4. Agregue un atributo DataSourceAttribute a este.

  5. Use la propiedad de indexador DataRow para recuperar los valores que se usan en una prueba.

Creación de un origen de datos

Para probar el método AddIntegers, cree un origen de datos que especifica un intervalo de valores para los parámetros y la suma que se espera que se devuelva. En este ejemplo, crearemos una base de datos de SQL Compact denominada MathsData y una tabla denominada AddIntegersData que contiene los siguientes nombres de columna y valores:

FirstNumber SecondNumber Sum
0 1 1
1 1 2
2 -3 -1

Agregar un TestContext para la clase de prueba

El marco de pruebas unitarias crea un objeto TestContext para almacenar la información de origen de datos para una prueba controlada por datos. Después, el marco de trabajo establece este objeto como el valor de la propiedad TestContext que crea.

public TestContext TestContext { get; set; }

En el método de prueba, accede a los datos a través de la propiedad de indizador DataRow del TestContext.

Nota

.NET Core no es compatible con el atributo DataSource. Si intenta acceder a los datos de prueba de esta forma en un proyecto de prueba unitaria de .NET Core, UWP o WinUI, se le mostrará un error similar al siguiente: "'TestContext' no contiene una definición para 'DataRow' ni un método de extensión accesible 'DataRow' que acepte un primer argumento del tipo 'TestContext' (¿falta alguna directiva using o una referencia de ensamblado?)".

Escribir el método de prueba

El método de prueba para AddIntegers es bastante sencillo. Para cada fila del origen de datos, llame a AddIntegers con los valores de columna FirstNumber y SecondNumber como parámetros y compruebe el valor devuelto con el valor de columna Sum:

[TestMethod]
[DataSource(@"Provider=Microsoft.SqlServerCe.Client.4.0; Data Source=C:\Data\MathsData.sdf;", "Numbers")]
public void AddIntegers_FromDataSourceTest()
{
    var target = new Maths();

    // Access the data
    int x = Convert.ToInt32(TestContext.DataRow["FirstNumber"]);
    int y = Convert.ToInt32(TestContext.DataRow["SecondNumber"]);
    int expected = Convert.ToInt32(TestContext.DataRow["Sum"]);
    int actual = target.AddIntegers(x, y);
    Assert.AreEqual(expected, actual,
        "x:<{0}> y:<{1}>",
        new object[] {x, y});
}

Especificación de DataSourceAttribute

El atributo DataSource especifica la cadena de conexión para el origen de datos y el nombre de la tabla que se utiliza en el método de prueba. La información exacta de la cadena de conexión es diferente, dependiendo de qué tipo de origen de datos está utilizando. En este ejemplo, se utiliza una base de datos de SqlServerCe.

[DataSource(@"Provider=Microsoft.SqlServerCe.Client.4.0;Data Source=C:\Data\MathsData.sdf", "AddIntegersData")]

El atributo de origen de datos tiene tres constructores.

[DataSource(dataSourceSettingName)]

Un constructor con un parámetro usa la información de conexión que se almacena en el archivo app.config para la solución. El dataSourceSettingsName es el nombre del elemento Xml en el archivo de configuración que especifica la información de conexión.

Un archivo app.config permite cambiar la ubicación del origen de datos sin realizar cambios en la propia prueba unitaria. Para obtener información sobre cómo crear y utilizar un archivo app.config, vea Tutorial: Usar un archivo de configuración para definir un origen de datos.

[DataSource(connectionString, tableName)]

El constructor DataSource con dos parámetros especifica la cadena de conexión para el origen de datos y el nombre de la tabla que contiene los datos para el método de prueba.

Las cadenas de conexión dependen del tipo de origen de datos, pero debe contener un elemento de proveedor que especifique el nombre invariable del proveedor de datos.

[DataSource(
    dataProvider,
    connectionString,
    tableName,
    dataAccessMethod
    )]

Uso de TestContext.DataRow para acceder a los datos

Para obtener acceso a los datos de la tabla AddIntegersData, utilice el indizador TestContext.DataRow. DataRow es un objeto DataRow, por lo que se recuperan valores de columna mediante los nombres de columna o índice. Dado que los valores se devuelven como objetos, es necesario convertirlos al tipo adecuado:

int x = Convert.ToInt32(TestContext.DataRow["FirstNumber"]);

Ejecutar la prueba y ver los resultados

Cuando haya terminado de escribir un método de prueba, compile el proyecto de prueba. El método de prueba aparece en el Explorador de pruebas en el grupo Pruebas no ejecutadas. Al ejecutar, escribir y volver a ejecutar las pruebas, el Explorador de pruebas muestra los resultados en los grupos de Pruebas no superadas, Pruebas superadas y Pruebas no ejecutadas. Se puede elegir Ejecutar todas para ejecutar todas las pruebas o bien Ejecutar para elegir un subconjunto de pruebas que se desea ejecutar.

Al ejecutar la prueba, se anima la barra de resultados de pruebas en la parte superior del Explorador de pruebas. Al final de la serie de pruebas, la barra será verde si todas las pruebas se completaron correctamente o roja si no alguna de las pruebas no lo hace. Un resumen de la ejecución de la prueba aparece en el panel de detalles de la parte inferior de la ventana Explorador de pruebas. Seleccione una prueba para ver los detalles de esa prueba en el panel inferior.

Nota

Hay un resultado para cada fila de datos y también un resumen de resultados. Si la prueba se supera en cada fila de datos, el resumen de la ejecución se mostrará como Superado. Si la prueba no se supera en alguna fila de datos, el resumen de la ejecución se mostrará como No superado.

Si ha ejecutado el método AddIntegers_FromDataRowTest, AddIntegers_FromDynamicDataTest o AddIntegers_FromDataSourceTest del ejemplo, la barra de resultados se vuelve roja y el método de prueba se mueve al grupo Pruebas no superadas. Se produce un error en una prueba controlada por datos si se produce un error en cualquiera de los métodos iterados del origen de datos. Al elegir una prueba controlada por datos con errores en la ventana Explorador de pruebas, en el panel de detalles se muestran los resultados de cada iteración que se identifica mediante el índice de fila de datos. En nuestro ejemplo, parece que el algoritmo AddIntegers no controla correctamente los valores negativos.

Cuando el método de prueba se ha corregido y la prueba se ejecuta de nuevo, la barra de resultados se vuelve verde y el método de prueba se mueve al grupo Pasa la prueba.