Bibliotecas de F# de prueba unitaria con pruebas de dotnet y NUnit
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, consulte 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.
Requisitos previos
- SDK de .NET 8 o versiones posteriores.
- Un editor de texto o un editor de código de su elección.
Creación del 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 el comando siguiente para crear un archivo de solución nuevo para la biblioteca de clases y el proyecto de prueba:
dotnet new sln
A continuación, cree un directorio MathService. En el esquema siguiente se muestra 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 el siguiente comando para crear el proyecto de origen:
dotnet new classlib -lang "F#"
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 el siguiente comando para agregar el proyecto de biblioteca de clases a la solución:
dotnet sln add .\MathService\MathService.fsproj
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 el comando siguiente:
dotnet new nunit -lang "F#"
Este comando crea un proyecto de prueba que usa NUnit como marco de pruebas. La plantilla generada configura el ejecutor de pruebas en MathServiceTests.fsproj:
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.9.0" />
<PackageReference Include="NUnit" Version="4.1.0" />
<PackageReference Include="NUnit3TestAdapter" Version="4.5.0" />
</ItemGroup>
El proyecto de prueba requiere otros paquetes para crear y ejecutar pruebas unitarias. En el paso anterior, dotnet new
agrega NUnit y el adaptador de prueba NUnit. 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
MathService.Tests.fsproj
Ejecute el comando siguiente en el directorio unit-testing-with-fsharp:
dotnet sln add .\MathService.Tests\MathService.Tests.fsproj
Creación de la primera prueba
Escribirá una prueba de errores, la aprobará y, luego, repetirá el proceso. Abra UnitTest1.fs y agregue el código siguiente:
namespace MathService.Tests
open System
open NUnit.Framework
open MathService
[<TestFixture>]
type TestClass () =
[<Test>]
member this.TestMethodPassing() =
Assert.That(true, Is.True)
[<Test>]
member this.FailEveryTime() = Assert.That(false, Is.True)
El atributo [<TestFixture>]
indica una clase que contiene pruebas. El atributo [<Test>]
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 NUnit 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 secuencia 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. Superar cada prueba significa crear la funcionalidad necesaria para el método.
La prueba más sencilla que 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:
[<Test>]
member this.TestEvenSequence() =
let expected = Seq.empty<int>
let actual = MyMath.squaresOfOdds [2; 4; 6; 8; 10]
Assert.That(actual, Is.EqualTo(expected))
Observe que la secuencia expected
se ha convertido en una lista. El marco de NUnit 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. Esto se debe a que aún no ha creado la implementación. Haga que esta prueba se supere escribiendo el código más simple de la clase Library.fs en su proyecto MathService que funciona:
let squaresOfOdds xs =
Seq.empty<int>
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, las pruebas se ejecutan. Ahora se superan dos pruebas.
Cumplimiento 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:
[<Test>]
member public this.TestOnesAndEvens() =
let expected = [1; 1; 1; 1]
let actual = MyMath.squaresOfOdds [2; 1; 4; 1; 6; 1; 8; 1; 10]
Assert.That(actual, Is.EqualTo(expected))
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
Falta un paso todavía: el cuadrado de cada uno de los números impares. Comience escribiendo una prueba nueva:
[<Test>]
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.That(actual, Is.EqualTo(expected))
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
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 forma parte del flujo de trabajo normal. Ha centrado la mayor parte de su tiempo y esfuerzo en resolver los objetivos de la aplicación.