Bibliotecas de F# de prueba unitaria en .NET Core con pruebas de dotnet y MSTest

Este tutorial le guía por una experiencia interactiva de creación de una solución de ejemplo paso a paso para aprender los conceptos de pruebas unitarias. Si prefiere seguir el tutorial con una solución precompilada, vea o descargue el código de ejemplo antes de comenzar. Para obtener instrucciones de descarga, vea Ejemplos y tutoriales.

Este artículo trata sobre la prueba de un proyecto de .NET Core. Si está realizando pruebas con un proyecto de ASP.NET Core, consulte Pruebas de integración en ASP.NET Core.

Crear el proyecto de origen

Abra una ventana del Shell. Cree un directorio llamado unit-testing-with-fsharp que contenga la solución. En este directorio nuevo, ejecute dotnet new sln para crear una solución nueva. Esto permite facilitar la administración de la biblioteca de clases y del proyecto de prueba unitaria. En el directorio de la solución, cree un directorio MathService. Esta es la estructura de directorios y archivos hasta el momento:

/unit-testing-with-fsharp
    unit-testing-with-fsharp.sln
    /MathService

Convierta MathService en el directorio actual y ejecute dotnet new classlib -lang "F#" para crear el proyecto de origen. Creará una implementación de errores del servicio de matemáticas:

module MyMath =
    let squaresOfOdds xs = raise (System.NotImplementedException("You haven't written a test yet!"))

Cambie nuevamente el directorio al directorio unit-testing-with-fsharp. Ejecute dotnet sln add .\MathService\MathService.fsproj para agregar el proyecto de biblioteca de clases a la solución.

Crear el proyecto de prueba

A continuación, cree el directorio MathService.Tests. En el esquema siguiente se muestra la estructura de directorios:

/unit-testing-with-fsharp
    unit-testing-with-fsharp.sln
    /MathService
        Source Files
        MathService.fsproj
    /MathService.Tests

Convierta el directorio MathService.Tests en el directorio actual y cree un proyecto nuevo con dotnet new mstest -lang "F#". Esto crea un proyecto de prueba que usa MSTest como el marco de pruebas. La plantilla generada configura el ejecutor de pruebas en MathServiceTests.fsproj:

<ItemGroup>
  <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0-preview-20170628-02" />
  <PackageReference Include="MSTest.TestAdapter" Version="1.1.18" />
  <PackageReference Include="MSTest.TestFramework" Version="1.1.18" />
</ItemGroup>

El proyecto de prueba requiere otros paquetes para crear y ejecutar pruebas unitarias. dotnet new en el paso anterior agregó MSTest y el ejecutor de MSTest. Ahora, agregue la biblioteca de clases MathService como otra dependencia al proyecto. Use el comando dotnet add reference:

dotnet add reference ../MathService/MathService.fsproj

Puede ver todo el archivo en el repositorio de muestras en GitHub.

Tiene el diseño de solución final siguiente:

/unit-testing-with-fsharp
    unit-testing-with-fsharp.sln
    /MathService
        Source Files
        MathService.fsproj
    /MathService.Tests
        Test Source Files
        MathServiceTests.fsproj

Ejecute dotnet sln add .\MathService.Tests\MathService.Tests.fsproj en el directorio unit-testing-with-fsharp.

Crear la primera prueba

Escribirá una prueba de errores, la aprobará y, luego, repetirá el proceso. Abra Tests.fs y agregue el código siguiente:

namespace MathService.Tests

open System
open Microsoft.VisualStudio.TestTools.UnitTesting
open MathService

[<TestClass>]
type TestClass () =

    [<TestMethod>]
    member this.TestMethodPassing() =
        Assert.IsTrue(true)

    [<TestMethod>]
     member this.FailEveryTime() = Assert.IsTrue(false)

El atributo [<TestClass>] indica una clase que contiene pruebas. El atributo [<TestMethod>] indica un método de prueba que el ejecutor de pruebas ejecuta. En el directorio unit-testing-with-fsharp, ejecute dotnet test para compilar las pruebas y la biblioteca de clases y luego ejecutar las pruebas. El ejecutor de pruebas de MSTest tiene el punto de entrada del programa para ejecutar las pruebas desde la consola. dotnet test inicia el ejecutor de pruebas con el proyecto de prueba unitaria que creó.

Estas dos pruebas muestran las pruebas superadas y con errores más básicas. My test indica que se supera y Fail every time indica que no. Ahora, cree una prueba para el método squaresOfOdds. El método squaresOfOdds devuelve una lista de los cuadrados de todos los valores enteros impares que forman parte de la secuencia de entrada. En lugar de intentar escribir todas esas funciones a la vez, puede crear de forma iterativa pruebas que validen la funcionalidad. Hacer cada prueba superada significa crear la funcionalidad necesaria para el método.

La prueba más sencilla que se puede escribir es llamar a squaresOfOdds con todos los números impares, donde el resultado sea una secuencia de enteros vacía. Aquí se muestra la prueba:

[<TestMethod>]
member this.TestEvenSequence() =
    let expected = Seq.empty<int> |> Seq.toList
    let actual = MyMath.squaresOfOdds [2; 4; 6; 8; 10]
    Assert.AreEqual(expected, actual)

Observe que la secuencia expected se convirtió en lista. La biblioteca de MSTest se basa en muchos tipos de .NET estándar. Esa dependencia significa que la interfaz pública y los resultados esperados admiten ICollection en lugar de IEnumerable.

Cuando ejecuta la prueba, se observa que no se supera la prueba. Todavía no ha creado la implementación. Cree esta prueba que se supera escribiendo el código más simple en la clase Mathservice que funciona:

let squaresOfOdds xs =
    Seq.empty<int> |> Seq.toList

En el directorio unit-testing-with-fsharp, vuelva a ejecutar dotnet test. El comando dotnet test ejecuta una compilación del proyecto MathService y luego del proyecto MathService.Tests. Después de compilar ambos proyectos, se ejecuta esta única prueba. Pasa.

Finalización de los requisitos

Ahora que la prueba se ha superado, es el momento de escribir más. El próximo caso simple funciona con una secuencia cuyo único número impar es 1. El número 1 es más simple, porque el cuadrado de 1 es 1. Aquí está la prueba siguiente:

[<TestMethod>]
member public this.TestOnesAndEvens() =
    let expected = [1; 1; 1; 1]
    let actual = MyMath.squaresOfOdds [2; 1; 4; 1; 6; 1; 8; 1; 10]
    Assert.AreEqual(expected, actual)

Si se ejecuta dotnet test, la prueba nueva se falla. Debe actualizar el método squaresOfOdds para controlar esta prueba nueva. Debe filtrar todos los números impares y quitarlos de la secuencia para que se supere esta prueba. Para hacerlo, escriba una función de filtro pequeña y use Seq.filter:

let private isOdd x = x % 2 <> 0

let squaresOfOdds xs =
    xs
    |> Seq.filter isOdd |> Seq.toList

Observe la llamada a Seq.toList. Esa acción crea una lista, que implemente la interfaz ICollection.

Falta un paso todavía: el cuadrado de cada uno de los números impares. Comience escribiendo una prueba nueva:

[<TestMethod>]
member public this.TestSquaresOfOdds() =
    let expected = [1; 9; 25; 49; 81]
    let actual = MyMath.squaresOfOdds [1; 2; 3; 4; 5; 6; 7; 8; 9; 10]
    Assert.AreEqual(expected, actual)

Puede corregir la prueba si canaliza la secuencia filtrada a través de una operación de asignación para calcular el cuadrado de cada número impar:

let private square x = x * x
let private isOdd x = x % 2 <> 0

let squaresOfOdds xs =
    xs
    |> Seq.filter isOdd
    |> Seq.map square
    |> Seq.toList

Ha creado una biblioteca pequeña y un conjunto de pruebas unitarias para esa biblioteca. Ha estructurado la solución, por lo que agregar pruebas y paquetes nuevos es parte del flujo de trabajo normal. Ha centrado la mayor parte del tiempo y del esfuerzo en resolver los objetivos de la aplicación.

Consulte también