NUnit 사용 단위 테스트(Unit Test)
이 강의에서는 NUnit 테스트 프레임워크를 사용하여 단위 테스트를 진행하는 방법을 단계별로 진행합니다.
사전 요구 사항
- .NET 7
- Visual Studio 2022
원본 프로젝트 만들기
VisualAcademy 솔루션에 Domain.UnitTests 이름으로 C# 클래스 라이브러리 프로젝트를 생성합니다.
셸 창을 엽니다. 솔루션을 저장하기 위한 VisualAcademy라는 폴더를 만듭니다. 이 새 디렉터리 내에서 다음 명령을 실행하여 클래스 라이브러리 및 테스트 프로젝트에 대한 새 솔루션 파일을 만듭니다.
dotnet new sln
다음으로 PrimeService 폴더를 만듭니다. 다음 개요는 지금까지의 디렉터리와 파일 구조를 보여 줍니다.
/VisualAcademy
VisualAcademy.sln
/PrimeService
PrimeService 폴더로 이동하고 다음 명령을 실행하여 소스 프로젝트를 만듭니다. 단위 테스트를 위한 C# 클래스 라이브러리 프로젝트입니다.
dotnet new classlib
Class1.cs의 이름을 PrimeService.cs로 바꿉니다. 다음과 같이 PrimeService
클래스의 실패 구현을 만듭니다.
using System;
namespace Prime.Services
{
public class PrimeService
{
public bool IsPrime(int candidate)
{
throw new NotImplementedException("먼저 테스트를 만드세요.");
}
}
}
폴더를 다시 VisualAcademy 디렉터리로 변경합니다. 다음 명령을 실행하여 클래스 라이브러리 프로젝트를 솔루션에 추가합니다. 물론 Visual Studio에서 직접 진행해도 됩니다.
dotnet sln add PrimeService/PrimeService.csproj
테스트 프로젝트 만들기
NUnit 프레임워크 관련 패키지
클래스 라이브러리 프로젝트에 NUnit 테스트 프레임워크를 사용하려면 다음 3개의 NuGet 패키지를 설치해야 합니다.
NUnit
NUnit3TestAdapter
Microsoft.NET.Test.Sdk
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.0" />
<PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
</ItemGroup>
Domain.UnitTests 프로젝트
PrimeService.Tests 프로젝트
다음으로 PrimeService.Tests
폴더를 만듭니다. 다음 개요에는 디렉터리 구조가 나와 있습니다.
/VisualAcademy
VisualAcademy.sln
/PrimeService
Source Files
PrimeService.csproj
/PrimeService.Tests
PrimeService.Tests
폴더로 이동하고 다음 명령을 사용하여 새 프로젝트를 만듭니다.
dotnet new nunit
dotnet new
명령은 NUnit를 테스트 라이브러리로 사용하는 테스트 프로젝트를 만듭니다. 생성된 템플릿은 PrimeService.Tests.csproj 파일에 Test Runner를 구성합니다.
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.3.0" />
<PackageReference Include="NUnit" Version="3.13.3" />
<PackageReference Include="NUnit3TestAdapter" Version="4.2.1" />
</ItemGroup>
테스트 프로젝트는 다른 패키지에 단위 테스트를 만들고 실행하도록 요구합니다. dotnet new
이전 단계의 명령은 Microsoft 테스트 SDK, NUnit 테스트 프레임워크 및 NUnit 테스트 어댑터를 추가했습니다. 이제 PrimeService
클래스 라이브러리를 프로젝트에 다른 종속성으로 추가합니다. dotnet add reference
명령을 사용합니다.
dotnet add reference ../PrimeService/PrimeService.csproj
GitHub의 샘플 리포지토리에서 전체 파일을 볼 수 있습니다.
다음 개요에는 최종 솔루션 레이아웃이 나와 있습니다.
/VisualAcademy
VisualAcademy.sln
/PrimeService
Source Files
PrimeService.csproj
/PrimeService.Tests
Test Source Files
PrimeService.Tests.csproj
VisualAcademy 디렉터리에서 다음 명령을 실행합니다.
dotnet sln add ./PrimeService.Tests/PrimeService.Tests.csproj
NUnit 테스트 특성
[TestFixture]
: 테스트를 포함하는 클래스에 지정[Test]
: 테스트 메서드에 지정[SetUp]
: 테스트 실행 전에 먼저 실행할 코드 지정(생성자와 비슷)[Category]
: 카테고리로 조직화할 때 사용[TestCase]
: 하나 이상의 데이터를 매개 변수로 전달해서 테스트[Values]
: 매개 변수로 전달할 값 리스트[Sequential]
: 테스트 데이터 조합[OneTimeSetup]
: 테스트 실행 전에 딱 한 번 실행할 기능
NUnit 어설션(Assertions)
Assert.That()
Assert.AreEqual()
Arrange, Act, Assert
- Arrange: 준비
- Act: 실행
- Assert: 확인
첫 번째 테스트 만들기
Domain.UnitTests
코드: TodoTests.cs
using Domain.Entities;
using NUnit.Framework;
namespace Domain.UnitTests.Entities;
[TestFixture]
public class TodoTests
{
private Todo _todo = null!;
private const int Id = 1;
private const string Name = "Test";
[SetUp]
public void SetUp()
{
_todo = new Todo();
}
[Test]
public void TestSetAndGetId()
{
_todo.Id = Id;
Assert.That(_todo.Id, Is.EqualTo(Id));
}
[Test]
public void TestSetAndGetName()
{
_todo.Name = Name;
Assert.That(_todo.Name, Is.EqualTo(Name));
}
}
코드: BrothTests.cs
using Domain.Entities.Buffets;
using NUnit.Framework;
namespace Domain.UnitTests.Entities.Buffets;
[TestFixture]
public class BrothTests
{
private Broth _broth = null!;
private const int Id = 1;
private const string Name = "콩국물";
[SetUp]
public void SetUp()
{
_broth = new Broth();
}
[Test]
public void TestSetAndGetId()
{
_broth.Id = Id;
Assert.That(_broth.Id,
Is.EqualTo(Id));
}
[Test]
public void TestSetAndGetName()
{
_broth.Name = Name;
Assert.That(_broth.Name,
Is.EqualTo(Name));
}
}
Prime.UnitTests
실패한 테스트 하나를 작성하고 통과한 다음 프로세스를 반복합니다. PrimeService.Tests 디렉터리에서 UnitTest1.cs 파일의 이름을 PrimeService_IsPrimeShould.cs로 변경하고 전체 내용을 다음 코드로 바꿉니다.
using NUnit.Framework;
using Prime.Services;
namespace Prime.UnitTests.Services
{
[TestFixture]
public class PrimeService_IsPrimeShould
{
private PrimeService _primeService;
[SetUp]
public void SetUp()
{
_primeService = new PrimeService();
}
[Test]
public void IsPrime_InputIs1_ReturnFalse()
{
var result = _primeService.IsPrime(1);
Assert.IsFalse(result, "1 should not be prime");
}
}
}
[TestFixture]
특성은 단위 테스트가 포함된 클래스를 나타냅니다. [Test]
특성은 메서드가 테스트 메서드임을 나타냅니다.
이 파일을 저장하고 명령을 실행 dotnet test
하여 테스트 및 클래스 라이브러리를 빌드하고 테스트를 실행합니다. NUnit Test Runner에는 테스트를 실행할 프로그램 진입점이 포함되어 있습니다. dotnet test
는 만든 단위 테스트 프로젝트를 사용하여 Test Runner를 시작합니다.
테스트가 실패합니다. 구현은 아직 만들지 않았습니다. 작동하는 클래스에서 PrimeService
가장 간단한 코드를 작성하여 테스트를 통과합니다.
public bool IsPrime(int candidate)
{
if (candidate == 1)
{
return false;
}
throw new NotImplementedException("먼저 테스트를 만드세요.");
}
VisualAcademy
디렉터리에서 dotnet test
를 다시 실행합니다. dotnet test
명령은 PrimeService
프로젝트에 대한 빌드를 실행한 다음 PrimeService.Tests
프로젝트에 대한 빌드를 실행합니다. 두 프로젝트를 모두 빌드한 후 이 단일 테스트를 실행합니다. 전달합니다.
더 많은 기능 추가
이제 하나의 테스트를 통과했으므로 더 작성할 수 있습니다. 0
과 -1
을 추가로 입력하는 다른 간단한 테스트 사례가 있습니다. 새 테스트를 [Test]
특성과 함께 추가할 수도 있지만, 이렇게 하면 금방 지루해질 수 있습니다. 유사한 테스트 모음을 작성하는 데 사용할 수 있는 다른 NUnit 특성이 있습니다. [TestCase]
특성은 같은 코드를 실행하는 테스트 모음을 만드는 데 사용되지만, 서로 다른 입력 인수를 가지고 있습니다. [TestCase]
특성을 사용하여 그러한 입력의 값을 지정할 수 있습니다.
새 테스트를 만드는 대신 이 특성을 적용하여 단일 데이터 기반 테스트를 만듭니다. 이 데이터 기반 테스트는 가장 작은 소수인 2보다 작은 몇 가지 값을 테스트하는 메서드입니다.
[TestCase(-1)]
[TestCase(0)]
[TestCase(1)]
public void IsPrime_ValuesLessThan2_ReturnFalse(int value)
{
var result = _primeService.IsPrime(value);
Assert.IsFalse(result, $"{value}은(는) 소수가 아닙니다.");
}
[TestCase(-1)]
[TestCase(0)]
[TestCase(1)]
public void IsPrime_ValuesLessThan2_ReturnFalse(int value)
{
var result = _primeService.IsPrime(value);
Assert.IsFalse(result, $"{value} should not be prime");
}
dotnet test
를 실행합니다. 그러면 이러한 테스트 중 2개가 실패합니다. 모든 테스트를 통과하려면 PrimeService.cs 파일에서 Main
메서드의 시작 부분에 있는 if
절을 변경합니다.
if (candidate < 2)
기본 라이브러리에 더 많은 테스트, 이론 및 코드를 추가하여 계속 반복합니다.
작은 라이브러리 및 이 라이브러리에 대한 단위 테스트 집합을 작성했습니다. 또한 새 패키지 및 테스트를 추가하는 것이 표준 워크플로의 일부가 되도록 솔루션을 구성했습니다. 애플리케이션의 목표를 해결하는 데 대부분의 시간과 노력을 들였습니다.
좋은 테스트의 조건
- 빠른 테스트
- 반복 가능 테스트
- 독립적 테스트
- 테스트 결과에 대한 확인