dotnet 테스트 및 TUnit을 사용하여 F# 라이브러리 단위 테스트

이 자습서에서는 단위 테스트 개념을 알아보기 위해 샘플 솔루션을 단계별로 빌드하는 대화형 환경을 안내합니다.

이 문서에서는 .NET Core 프로젝트를 테스트하는 방법에 대해 알아봅니다. ASP.NET Core 프로젝트를 테스트하는 경우 ASP.NET Core 통합 테스트를 참조하세요.

Prerequisites

  • .NET 10 SDK 또는 그 이후 버전.
  • 선택하는 텍스트 편집기 또는 코드 편집기입니다.

TUnit은 전적으로 Microsoft.Testing.Platform (MTP)를 기반으로 빌드되며 VSTest를 지원하지 않습니다. 이 자습서에서는 dotnet test의 MTP 모드를 사용하며, 이 모드에는 .NET 10 SDK가 필요합니다.

원본 프로젝트 만들기

셸 창을 엽니다. 솔루션을 저장할 unit-testing-with-fsharp 라는 디렉터리를 만듭니다. 이 새 디렉터리 내에서 다음 명령을 실행하여 클래스 라이브러리 및 테스트 프로젝트에 대한 새 솔루션 파일을 만듭니다.

dotnet new sln

다음으로 MathService 디렉터리를 만듭니다. 다음 개요는 지금까지의 디렉터리 및 파일 구조를 보여줍니다.

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

MathService를 현재 디렉터리로 만들고 다음 명령을 실행하여 원본 프로젝트를 만듭니다.

dotnet new classlib -lang "F#"

Library.fs의 내용을 수학 서비스의 의도적으로 실패하는 구현으로 바꿉니다.

namespace MathService

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

디렉터리를 다시 unit-testing-with-fsharp 디렉터리로 변경합니다. 다음 명령을 실행하여 솔루션에 클래스 라이브러리 프로젝트를 추가합니다.

dotnet sln add ./MathService/MathService.fsproj

테스트 프로젝트 만들기

다음으로 MathService.Tests 디렉터리를 만듭니다. 다음 개요는 디렉터리 구조를 보여줍니다.

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

TUnit 프로젝트 템플릿은 .NET SDK에 포함되지 않습니다. 다음 명령을 사용하여 설치합니다.

dotnet new install TUnit.Templates

MathService.Tests 디렉터리를 현재 디렉터리로 만들고 다음 명령을 사용하여 새 프로젝트를 만듭니다.

dotnet new TUnit -lang "F#"

Note

템플릿 짧은 이름은 대/소문자를 구분합니다. TUnit이 아니라 tunit을 사용합니다.

이 명령은 TUnit을 테스트 프레임워크로 사용하는 테스트 프로젝트를 만듭니다. 생성된 MathService.Tests.fsproj 파일은 테스트 프레임워크, 어설션 라이브러리 및 MTP 테스트 러너를 포함하는 TUnit.Assertions.FSharp 패키지와 어설션에 대한 F# 도우미를 추가하는 TUnit 패키지를 참조하는 실행 가능한 프로젝트입니다.

템플릿은 샘플 테스트도 추가합니다. 이 자습서에서는 그것들을 Tests.fs에 있는 자체 테스트로 대체합니다. 데이터 디렉터리 및 GlobalSetup.fs, Tests2.fs 및 Tests3.fs 파일을 삭제합니다. F# 프로젝트는 소스 파일을 명시적으로 나열하므로 ItemGroup에서 Compile 항목을 포함하는 도 다음 내용으로 바꿉니다.

<ItemGroup>
  <Compile Include="Tests.fs" />
</ItemGroup>

이제 MathService 클래스 라이브러리를 프로젝트에 다른 종속성으로 추가합니다. dotnet reference add 명령을 사용합니다.

dotnet reference add ../MathService/MathService.fsproj

다음 개요는 최종 솔루션 레이아웃을 보여줍니다.

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

unit-testing-with-fsharp 디렉터리에서 다음 명령을 실행합니다.

dotnet sln add ./MathService.Tests/MathService.Tests.fsproj

dotnet test의 MTP 모드 구성

TUnit dotnet test은 VSTest를 지원하지 않으므로 MTP 모드로 실행되어야 합니다. unit-testing-with-fsharp 디렉터리에서 다음 내용으로 global.json 파일을 만듭니다.

{
    "test": {
        "runner": "Microsoft.Testing.Platform"
    }
}

자세한 내용은 dotnet 테스트의 MTP 모드를 참조하세요.

첫 번째 테스트 만들기

실패한 테스트 하나를 작성하고 통과한 다음 프로세스를 반복합니다. Tests.fs의 내용을 다음 코드로 바꿉니다.

namespace MathService.Tests

open TUnit.Core
open TUnit.Assertions
open TUnit.Assertions.Extensions
open TUnit.Assertions.FSharp.TaskAssert
open MathService

type TestClass () =

    [<Test>]
    member this.TestMethodPassing() = taskAssert {
        do! Assert.That(true).IsTrue()
    }

    [<Test>]
    member this.FailEveryTime() = taskAssert {
        do! Assert.That(false).IsTrue()
    }

이 특성은 [<Test>] 테스트 실행기에서 실행하는 테스트 메서드를 표시합니다. TUnit은 클래스의 멤버인 테스트 메서드를 검색합니다. 모듈에서 선언된 let 함수는 검색하지 않습니다. TUnit 어설션은 비동기적입니다. TUnit.Assertions.FSharp의 계산 식 taskAssert은 테스트를 작업으로 실행하고 do!로 각 어설션을 대기할 수 있도록 합니다.

unit-testing-with-fsharp 디렉터리에서 실행 dotnet test 하여 테스트 및 클래스 라이브러리를 빌드한 다음 테스트를 실행합니다. TUnit 테스트 프로젝트에는 테스트를 실행할 프로그램 진입점이 포함되어 있습니다. dotnet test 는 만든 단위 테스트 프로젝트를 사용하여 테스트 애플리케이션을 시작합니다.

이 두 테스트는 가장 기본적인 통과 및 실패 테스트를 보여 줍니다. TestMethodPassing은 통과하고 FailEveryTime은 실패합니다. 이제 메서드에 대한 테스트를 만듭니다 squaresOfOdds . 이 메서드는 squaresOfOdds 입력 시퀀스의 일부인 모든 홀수 정수 값의 제곱 시퀀스를 반환합니다. 이러한 모든 함수를 한 번에 작성하는 대신 기능의 유효성을 검사하는 테스트를 반복적으로 만들 수 있습니다. 각 테스트를 통과하려면 메서드를 위한 필요한 기능을 만듭니다.

작성할 수 있는 가장 간단한 테스트는 모든 짝수로 호출 squaresOfOdds 하는 것입니다. 여기서 결과는 빈 정수 시퀀스여야 합니다. TestClass 유형에 다음 테스트를 추가합니다:

[<Test>]
member this.TestEvenSequence() = taskAssert {
    let expected = Seq.empty<int>
    let actual = MyMath.squaresOfOdds [2; 4; 6; 8; 10]
    do! Assert.That<int>(actual).IsEquivalentTo(expected)
}

F#은 메서드 오버로드를 해결할 때 C#보다 엄격하므로 테스트에서 정수 시퀀스에 대한 어설션을 선택하도록 Assert.That<int>에 항목 형식을 전달합니다. IsEquivalentTo 는 두 시퀀스에 동일한 항목이 포함되어 있는지 확인합니다.

테스트를 실행하면 테스트가 실패하는 것을 볼 수 있습니다. 구현을 아직 만들지 않았기 때문입니다. 작동하는 MathService 프로젝트의 Library.fs 파일에서 가장 간단한 코드를 작성하여 이 테스트를 통과하세요:

let squaresOfOdds xs =
    Seq.empty<int>

unit-testing-with-fsharp 디렉터리에서 다시 실행 dotnet test 합니다. dotnet test 명령은 MathService 프로젝트 및 MathService.Tests 프로젝트에 대한 빌드를 실행합니다. 두 프로젝트를 모두 빌드한 후 테스트를 실행합니다. 이제 두 개의 테스트가 통과합니다.

요구 사항 완료

이제 한 번의 테스트를 완료했으니 더 많은 테스트를 작성해야 합니다. 다음 간단한 사례는 홀수만 있는 시퀀스에서 작동합니다 1. 제곱 1이 1이므로 숫자 1이 더 쉽습니다. 다음 테스트는 다음과 같습니다.

[<Test>]
member public this.TestOnesAndEvens() = taskAssert {
    let expected = [1; 1; 1; 1]
    let actual = MyMath.squaresOfOdds [2; 1; 4; 1; 6; 1; 8; 1; 10]
    do! Assert.That<int>(actual).IsEquivalentTo(expected)
}

dotnet test을(를) 실행하면 새 테스트가 실패합니다. 이 새 테스트를 처리하려면 메서드를 업데이트 squaresOfOdds 해야 합니다. 이 테스트를 통과하려면 시퀀스에서 모든 짝수 수를 필터링해야 합니다. 이 작업은 작은 필터 함수를 작성하고 다음을 사용하여 수행할 수 있습니다 Seq.filter.

let private isOdd x = x % 2 <> 0

let squaresOfOdds xs =
    xs
    |> Seq.filter isOdd

다음 단계로 넘어가세요: 각 홀수를 제곱하세요. 먼저 새 테스트를 작성합니다.

[<Test>]
member public this.TestSquaresOfOdds() = taskAssert {
    let expected = [1; 9; 25; 49; 81]
    let actual = MyMath.squaresOfOdds [1; 2; 3; 4; 5; 6; 7; 8; 9; 10]
    do! Assert.That<int>(actual).IsEquivalentTo(expected)
}

맵 작업을 통해 필터링된 시퀀스를 파이핑하여 각 홀수의 제곱을 계산하여 테스트를 수정할 수 있습니다.

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

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

작은 라이브러리와 해당 라이브러리에 대한 단위 테스트 집합을 빌드했습니다. 새 패키지 및 테스트를 추가하는 것이 일반 워크플로의 일부가 되도록 솔루션을 구성했습니다. 대부분의 시간과 노력을 집중하여 애플리케이션의 목표를 해결했습니다.

또한, 다음을 참조하세요.