테스트 프로젝트와 단위 테스트
Visual Studio는 다양한 기능과 도구를 제공하는 강력한 개발 환경으로, 여러 가지 테스트 도구를 내장하고 있습니다.
이번 강의에서는 MSTest를 사용하여 C#으로 작성된 클래스 라이브러리 코드에 대한 **단위 테스트(Unit Test)**를 진행하는 방법을 알아보겠습니다.
> // 단위 테스트(Unit Test): 특정 클래스의 메서드에 있는 논리 오류를 빠르게 찾고, 이를 수정하는 데 도움을 주는 기능입니다.
자동 테스트(Automated Test)
테스트할 API에 대한 테스트 케이스를 미리 작성해 두면, 필요할 때마다 자동으로 해당 테스트를 실행할 수 있습니다.
자동 테스트를 도입하면 개발 과정에서 다음과 같은 이점을 얻을 수 있습니다.
- 코드의 오류를 신속하게 발견하고 수정할 수 있습니다.
- 수동 테스트보다 훨씬 빠르게 여러 개의 테스트를 자동으로 실행할 수 있습니다.
- 코드의 신뢰성과 품질을 검증하여 유지보수를 쉽게 할 수 있습니다.
다음 장에서는 MSTest 테스트 프로젝트를 생성하고 실행하는 방법을 살펴보겠습니다.
소프트웨어 테스트 방법 비교
단위 테스트 (Unit Tests)
단위 테스트는 소프트웨어의 **가장 작은 단위(함수 또는 메서드)**를 독립적으로 테스트하는 방법입니다.
이 테스트의 목적은 각 단위가 예상대로 동작하는지 확인하고, 버그를 조기에 발견하는 것입니다.
특징:
- 실행 속도가 빠르며, 자주 반복 실행할 수 있습니다.
- 개발자가 직접 작성하고 실행하는 경우가 많습니다.
- 외부 의존성(데이터베이스, API 등)은 **모의 개체(Mock objects)**로 대체하여 테스트합니다.
통합 테스트 (Integration Tests)
통합 테스트는 **두 개 이상의 단위(모듈 또는 컴포넌트)**가 함께 작동하는지를 검증하는 테스트입니다.
이 테스트의 목적은 단위들 간의 인터페이스 및 상호작용에서 발생할 수 있는 문제를 찾는 것입니다.
특징:
- 단위 테스트보다 더 복잡하며, 실행 속도가 상대적으로 느릴 수 있습니다.
- 시스템의 구조적 문제를 발견하는 데 유용합니다.
- 실제 환경과 유사한 조건에서 실행되는 것이 일반적이며, 데이터베이스 및 외부 API와 함께 작동할 수도 있습니다.
기능 테스트 (Functional Tests)
기능 테스트는 소프트웨어의 특정 기능이 사용자의 요구사항과 일치하는지 확인하는 테스트입니다.
이는 시스템 전체가 사용자의 기대대로 동작하는지 검증하는 것이 목적입니다.
특징:
- 사용자의 관점에서 소프트웨어를 평가하는 테스트입니다.
- 자동화된 스크립트를 활용하여 사용자 상호작용을 모방하는 경우가 많습니다.
- 전체 시스템이 정상적으로 작동하는지를 확인하며, UI 테스트와 연계될 수도 있습니다.
각 테스트 방법은 목적과 적용 범위가 다르며, 단위 테스트 → 통합 테스트 → 기능 테스트 순서로 점진적으로 검증을 확장해 나가는 것이 일반적입니다.
MSTest
MSTest는 Visual Studio에 기본 포함된 단위 테스트 프레임워크로, C# 개발자가 쉽게 사용할 수 있습니다.
.NET 환경에서는 여러 단위 테스트 프레임워크가 존재하며, 그중 대표적인 몇 가지는 다음과 같습니다.
- MSTest: 마이크로소프트에서 공식적으로 지원하는 단위 테스트 프레임워크
- NUnit: JUnit에서 영감을 받아 개발된, 널리 사용되는 오픈소스 단위 테스트 프레임워크
- xUnit: .NET 전용으로 설계된, 현대적인 기능을 갖춘 오픈소스 단위 테스트 프레임워크
MSTest는 Visual Studio와의 강력한 통합성을 제공하여, 기본적으로 설정 없이 단위 테스트를 바로 작성하고 실행할 수 있는 장점이 있습니다.
Assert
클래스의 주요 API
테스트 프로젝트에서 Assert
클래스는 테스트 결과를 검증하는 데 필수적인 역할을 합니다.
이 클래스는 다양한 메서드를 제공하여, 테스트 케이스의 성공 또는 실패 여부를 판단합니다.
주요 메서드
Assert.IsTrue(condition)
condition
값이true
일 경우 테스트가 통과됩니다.
Assert.IsNull(object)
object
값이null
이면 테스트가 통과됩니다.
Assert.AreEqual(expected, actual)
expected
값과actual
값이 같으면 테스트가 통과됩니다.
Assert.AreNotEqual(expected, actual)
expected
값과actual
값이 다르면 테스트가 통과됩니다.
이 외에도 Assert
클래스에는 다양한 검증 메서드가 포함되어 있으며,
더 많은 API 정보는 .NET API 탐색기를 통해 확인할 수 있습니다.
MSTest와 Assert
클래스를 활용하면, 코드의 동작을 보다 정확하게 검증하고 유지보수를 효율적으로 수행할 수 있습니다.
Arrange, Act, Assert와 Given, When, Then
단위 테스트를 작성할 때, 테스트 절차를 설명하는 데 자주 사용되는 용어들이 있습니다.
이는 테스트 코드의 구조를 명확하게 하고 가독성을 높이는 역할을 합니다.
- Arrange (Setup, Given)
- 테스트 환경을 설정하고, 필요한 데이터를 준비하는 단계
- Act (Execute, When)
- 실제 테스트할 코드를 실행하는 단계
- Assert (Verify, Then)
- 실행 결과를 검증하여 기대하는 결과와 일치하는지 확인하는 단계
이러한 절차를 따르면 테스트 코드가 직관적으로 구성되며, 유지보수가 용이해집니다.
특히, Given-When-Then 방식은 **행동 기반 개발(Behavior-Driven Development, BDD)**에서도 많이 활용됩니다.
[실습] 테스트 프로젝트 생성 및 Assert
클래스 사용하기
소개
Visual Studio에서 기본으로 제공하는 테스트 프로젝트 템플릿을 사용하여 테스트 프로젝트를 만들고 Assert
클래스를 사용해보는 시간을 갖도록 하겠습니다.
따라하기 1: Dul
솔루션에 Dul.Tests
프로젝트 추가
(1) 앞 장에서 작성한 Dul
솔루션을 엽니다. 현재까지 Dul
솔루션에는 닷넷 스탠다드 기반의 Dul
프로젝트와 Dul.App
이름의 콘솔 응용 프로그램이 작성되어 있습니다.
(2) 솔루션에 [새로 만들기]-[프로젝트]
를 진행하여 프로젝트 템플릿에서 MSTest 테스트 프로젝트(.NET)를 선택합니다. MSTest 이외에도 다른 테스트 프로젝트 템플릿이 목록에 나타날 것입니다.
그림: 테스트 프로젝트 추가하기
(3) 테스트 프로젝트 이름은 Dul.Tests로 설정합니다.
그림: 테스트 프로젝트 이름 지정하기
(4) 테스트 프로젝트가 생성되면 기본 생성된 UnitTest1.cs 파일은 삭제를 합니다. Dul.Tests
프로젝트는 Dul
프로젝트에 대한 테스트 프로젝트이기에 Dul
프로젝트의 [종속성] > [참조 추가]
를 선택합니다.
그림: 테스트 프로젝트에 참조 추가하기
(5) 참조 관리자 창이 나오면 닷넷 스탠다드(또는 닷넷 클래스 라이브러리) 프로젝트인 Dul
프로젝트를 테스트 프로젝트에 참조 추가하도록 체크박스를 체크한 후 [확인]
을 클릭합니다.
그림: 참조 관리자에서 Dul
프로젝트 참조하기
따라하기 2: 테스트 코드 작성 및 실행
(1) Dul.Tests
프로젝트에 00_Assert 폴더를 생성 후 AssertDemo.cs 클래스 파일을 생성합니다. 그리고 다음과 같이 코드를 작성합니다.
그림: AssertDemo.cs 파일 작성하기
실제 작성할 코드는 다음 코드를 참고하세요.
코드: AssertDemo.cs
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Dul.Tests
{
[TestClass]
public class AssertDemo
{
[TestMethod]
public void AssertAreEqualTest()
{
//Assert.AreEqual(
// expected: "비교할 첫 번째 개체",
// actual: "비교할 두 번째 개체");
Assert.AreEqual(1234, 1234);
}
}
}
참고로, 테스트 프로젝트 코드 내에서 testc
와 testm
코드 조각을 사용하면 편리하게 테스트 클래스와 테스트 메서드 모양을 만들 수 있습니다.
그림: 테스트 클래스와 테스트 메서드 코드 작성을 위한 코드 조각
(2) AssertAreEqualTest()
메서드 안쪽에 마우스를 두고 오른쪽 버튼을 누른 후 [테스트 실행]
을 진행합니다.
그림: 테스트 실행
(3) 한 줄 짜리 코드이고 에러없이 실행되기에 다음 그림과 같이 테스트 탐색기에 테스트가 통과되었다는 의미의 녹색(Green) 아이콘이 출력됩니다. 만약, 테스트 탐색기가 보이지 않는다면 [Visual Studio]-[테스트]-[창]-[테스트 탐색기]
메뉴를 선택하면 됩니다.
그림: 테스트 탐색기에서 테스트 실행 결과 확인하기
(4) 만약 actual
매개 변수의 값을 2345
와 같이 1234 != 2345
형태로 잘못된 데이터를 넣으면 다음 그림과 같이 빨간색(Red) 아이콘이 출력되고 테스트 실패 상세 메시지가 보여집니다.
그림: 테스트 탐색기에서 테스트 실패 확인하기
마무리
테스트 클래스의 테스트 메서드에서 사용되는 특별한 목적의 Assert
클래스를 사용해 보았습니다. 물론, 많은 수의 API 중에서 Assert.AreEqual()
메서드 하나만 살펴보았지만, 다른 메서드들도 사용법은 비슷합니다. 계속해서 우리가 직접 만든 API에 대한 테스트를 진행해 보겠습니다.
[실습] Dul
프로젝트 테스트를 위한 테스트 코드 작성 및 실행
소개
Visual Studio에서 테스트 프로젝트를 만들고 테스트 클래스와 테스트 메서드를 만들고 기존 또는 새롭게 만든 코드에 대해서 자동 테스트를 구현하는 방법을 단계별로 살펴보겠습니다.
따라하기 1: Dul
프로젝트에 새로운 API 추가하기
(1) Visual Studio를 실행하고 Dul
솔루션을 엽니다. 현재 Dul
솔루션의 구조는 다음과 같습니다.
그림: Dul
솔루션의 구조
- Dul.sln: 솔루션
- Dul.csproj: .NET Standard 2.0 클래스 라이브러리 프로젝트
- Dul.App.csproj: 콘솔 응용 프로그램(.NET Core)
- Dul.Tests.csproj: MSTest Test Project (.NET Core)
(2) 닷넷스탠다드 프로젝트인 Dul
프로젝트에 추가로 04_DateTime 폴더를 만들고 DateTimeUtility.cs 이름으로 클래스를 만들고 다음과 같이 코드를 작성합니다. ShowTimeOrDate()
이름의 유틸리티 메서드를 하나 만들 예정입니다.
그림: DateTimeUtility.cs 파일 추가하기
코드: DateTimeUtility.cs
using System;
using System.Collections.Generic;
namespace Dul
{
/// <summary>
/// 날짜와 시간 관련 유틸리티
/// </summary>
public class DateTimeUtility
{
/// <summary>
/// 날짜 형식이 오늘 날짜면 시간 표시 다르면 날짜 표시
/// </summary>
public static string ShowTimeOrDate(object dt, string format = "yyyy-MM-dd")
{
if (dt != null && DateTime.TryParse(dt.ToString(), out DateTime dateTime))
{
if (dateTime.Date == DateTime.Now.Date)
{
return dateTime.ToString("hh:mm:ss");
}
else
{
return dateTime.ToString(format); // "yyyy-MM-dd" || "yy-MM-dd"
}
}
else
{
return "";
}
}
}
}
(3) Dul.Tests
프로젝트에서는 이미 Dul
프로젝트에 대한 참조 추가가 되어 있기에 Dul
프로젝트에 새로운 클래스를 추가하고 솔루션을 다시 빌드하면 새로운 클래스가 적용된 Dul.dll 파일이 콘솔 또는 클래스 프로젝트에서 다시 참조가 됩니다.
따라하기 2: Dul
프로젝트의 주요 API 테스트하기
다음 그림과 같이 01_Creator 부터 04_DateTime 폴더까지 4개의 폴더와 클래스를 추가하고 각각의 메서드에 대한 테스트 코드를 작성하겠습니다. 각각의 코드는 테스트 클래스와 테스트 메서드를 자동으로 만들어주는 코드 조각인 testc
와 testm
를 사용해서 만들면 편합니다.
그림: 4개의 클래스에 대한 테스트 코드 작성하기
(1) MSTest 프로젝트인 Dul.Tests
프로젝트에 01_Creator/CreatorTest.cs 파일을 만들고 다음 테스트코드를 작성하고 테스트합니다. 테스트 코드의 3단계 주석을 잘 보면 Arrange, Act, Assert 순서로 테스트를 진행합니다.
코드: CreatorTest.cs
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Dul.Tests
{
[TestClass]
public class CreatorTest
{
[TestMethod]
public void GetNameTest()
{
//[1] Arrange(정렬), Setup
const string expected = "RedPlus";
//[2] Act(동작), Execute
var actual = Creator.GetName();
//[3] Assert(어설션), Verify
Assert.AreEqual(expected, actual);
}
}
}
Dul
클래스 라이브러리의 제작자 이름은 박용준 강사의 닉네임인 "RedPlus"로 설정이 되어있습니다. [1]
번 코드에서 예상값을 놓고 [2]
번 Execute 영역에서 실행된 결괏값을 받은 후 [3]
번 코드 영역인 Verity에서 예상값과 실행값이 같은지 또는 다른지 등을 검사하는 형태로 테스트가 진행됩니다. 만약, expected
변수에 다른 문자열을 입력하면 현재 테스트 메서드는 실행할 때 실패해서 Red 메시지가 출력됩니다. 단위 테스트는 Red에서 Green으로 결과를 바꾸어 가는 과정입니다.
(2) MSTest 프로젝트인 Dul.Tests
프로젝트에 02_Mathematics/Dul.Math.Abs.Test.cs 파일을 만들고 다음과 같이 테스트 코드를 작성하고 테스트를 실행합니다.
코드: Dul.Math.Abs.Test.cs
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Dul.Tests.Mathematics
{
[TestClass]
public class DulMathTest
{
[TestMethod]
public void AbsTest()
{
//[1] Arrange, Setup
var expected = 1234;
//[2] Act, Execute
var actual = Dul.Math.Abs(-1234);
//[3] Assert, Verify
Assert.AreEqual(expected, actual);
}
}
}
(3) MSTest 프로젝트인 Dul.Tests
프로젝트에 03_String/StringLibraryTest.cs 파일을 만들고 다음 테스트코드를 작성하고 테스트합니다. 이 테스트 메서드는 Dul
프로젝트의 03_String 폴더에 있는 StringLibrary.cs 파일의 CutStringUnicode()
확장 메서드를 테스트합니다.
코드: StringLibraryTest.cs
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Dul.Tests
{
[TestClass]
public class StringLibraryTest
{
[TestMethod]
public void CutStringTest()
{
//[1] Arrange, Setup
var expected = "안녕하...";
//[2] Act, Execute
var actual = "안녕하세요.".CutStringUnicode(6);
//[3] Assert, Verify
Assert.AreEqual(expected, actual);
}
}
}
(4) MSTest 프로젝트인 Dul.Tests
프로젝트에 04_DateTime/DateTimeUtilityTest.cs 파일을 만들고 다음 테스트코드를 작성하고 테스트합니다.
코드: DateTimeUtilityTest.cs
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System;
namespace Dul.Tests
{
[TestClass]
public class DateTimeUtilityTest
{
[TestMethod]
public void ShowTimeOrDateTest()
{
// (현재 시간 == 오늘 날짜) => 01:01:01 형태
var now = DateTime.Now;
var expeted = now.ToString("hh:mm:ss");
// [1] `Assert` 클래스의 주요 메서드를 사용하여 테스트 통과 확인
Assert.AreEqual(expeted, DateTimeUtility.ShowTimeOrDate(now));
}
[TestMethod]
public void ShowTimeOrDateTestOther()
{
// (현재 시간 != 오늘 날짜) => 2019-12-20 형태
var prev = DateTime.Now.AddDays(-7);
// [2] `Assert` 클래스 없이 직접 실행하는 경우는 테스트 바로 통과
// yyyy-MM-dd 형태
Console.WriteLine(DateTimeUtility.ShowTimeOrDate(prev));
// yy-MM-dd 형태
Console.WriteLine(DateTimeUtility.ShowTimeOrDate(prev, "yy-MM-dd"));
}
}
}
테스트 프로젝트 내에서 Console.WriteLine()
메서드를 호출하면 테스트 출력 창에서 그 내용을 확인할 수 있습니다.
그림: 테스트 결과 확인하기
(5) Dul.Tests
프로젝트에 마우스 오른쪽 버튼 클릭하여 [테스트 실행]
을 선택하면 프로젝트의 모든 테스트를 한꺼번에 실행합니다.
그림: 모든 테스트 실행하기
마무리
MSTest 프로젝트를 포함한 많은 수의 테스트 도구들은 C#으로 만든 API를 다양한 방법으로 테스트하는 방법을 제공합니다. 이번 실습 예제에서의 짧은 내용은 지금까지 우리가 만들었고 앞으로 우리가 만들 모든 API에 적용할 수 있는 부분입니다. 테스트 프로젝트를 만들고 테스트하는 작업은 코드를 더 많이 작성해야하지만, 만든 API에 대한 첫번째 검증 코드를 완성하는 과정이기에 되도록이면 하나의 API를 만들면 반드시 테스트 프로젝트에서 해당 API를 테스트하는 테스트 클래스와 테스트 메서드를 만들기를 권장합니다.
장 요약
단위 테스트를 편리하게 해주는 테스트 프로젝트는 좀 더 나아가 TDD(Test Driven Development) 형태로 프로그래밍을 할 수 있게 해줍니다. 너무 거창하게 생각할 필요없이, 닷넷에 있는 API가 아닌 사용자가 직접 만든 API는 직접 테스트 메서드를 만들어 테스트하는 습관을 들이면 됩니다.