다섯 번째 반복에서는 단위 테스트를 추가하여 애플리케이션을 더 쉽게 유지 관리하고 수정할 수 있습니다. 데이터 모델 클래스를 모의하고 컨트롤러 및 유효성 검사 논리에 대한 단위 테스트를 빌드합니다.
VB(연락처 관리 ASP.NET MVC 애플리케이션) 빌드
이 자습서 시리즈에서는 처음부터 끝까지 전체 연락처 관리 애플리케이션을 빌드합니다. Contact Manager 애플리케이션을 사용하면 사용자 목록에 대한 연락처 정보(이름, 전화 번호 및 전자 메일 주소)를 저장할 수 있습니다.
여러 반복을 통해 애플리케이션을 빌드합니다. 반복할 때마다 애플리케이션을 점진적으로 개선합니다. 이 여러 반복 방법의 목표는 각 변경의 이유를 이해할 수 있도록 하는 것입니다.
반복 #1 - 애플리케이션을 만듭니다. 첫 번째 반복에서는 가능한 가장 간단한 방법으로 연락처 관리자를 만듭니다. CRUD(만들기, 읽기, 업데이트 및 삭제)의 기본 데이터베이스 작업에 대한 지원을 추가합니다.
반복 #2 - 애플리케이션을 멋지게 만듭니다. 이 반복에서는 기본 ASP.NET MVC 보기 master 페이지 및 계단식 스타일시트를 수정하여 애플리케이션의 모양을 개선합니다.
반복 #3 - 양식 유효성 검사를 추가합니다. 세 번째 반복에서는 기본 양식 유효성 검사를 추가합니다. 사용자가 필요한 양식 필드를 완료하지 않고 양식을 제출하지 못하도록 합니다. 또한 전자 메일 주소 및 전화 번호의 유효성을 검사합니다.
반복 #4 - 애플리케이션을 느슨하게 결합합니다. 이 네 번째 반복에서는 여러 소프트웨어 디자인 패턴을 활용하여 Contact Manager 애플리케이션을 더 쉽게 유지 관리하고 수정할 수 있습니다. 예를 들어 리포지토리 패턴 및 종속성 주입 패턴을 사용하도록 애플리케이션을 리팩터링합니다.
반복 #5 - 단위 테스트 만들기 다섯 번째 반복에서는 단위 테스트를 추가하여 애플리케이션을 더 쉽게 유지 관리하고 수정할 수 있습니다. 데이터 모델 클래스를 모의하고 컨트롤러 및 유효성 검사 논리에 대한 단위 테스트를 빌드합니다.
반복 #6 - 테스트 기반 개발을 사용합니다. 이 여섯 번째 반복에서는 먼저 단위 테스트를 작성하고 단위 테스트에 대한 코드를 작성하여 애플리케이션에 새로운 기능을 추가합니다. 이 반복에서는 연락처 그룹을 추가합니다.
반복 #7 - Ajax 기능 추가 일곱 번째 반복에서는 Ajax에 대한 지원을 추가하여 애플리케이션의 응답성과 성능을 향상시킵니다.
이 반복
Contact Manager 애플리케이션의 이전 반복에서 애플리케이션을 더 느슨하게 결합하도록 리팩터링했습니다. 애플리케이션을 개별 컨트롤러, 서비스 및 리포지토리 계층으로 분리했습니다. 각 계층은 인터페이스를 통해 그 아래의 레이어와 상호 작용합니다.
애플리케이션을 더 쉽게 유지 관리하고 수정할 수 있도록 애플리케이션을 리팩터링했습니다. 예를 들어 새 데이터 액세스 기술을 사용해야 하는 경우 컨트롤러 또는 서비스 계층을 건드리지 않고 리포지토리 계층을 변경할 수 있습니다. Contact Manager를 느슨하게 결합함으로써 애플리케이션을 보다 탄력적으로 변경하도록 했습니다.
하지만 연락처 관리자 애플리케이션에 새 기능을 추가해야 하는 경우 어떻게 되나요? 또는 버그를 수정하면 어떻게 되나요? 코드 작성의 슬프지만 잘 입증된 진실은 코드를 터치할 때마다 새 버그를 도입할 위험이 있다는 것입니다.
예를 들어 하루가면 관리자가 연락처 관리자에 새 기능을 추가하도록 요청할 수 있습니다. 연락처 그룹에 대한 지원을 추가하려고 합니다. 사용자가 연락처를 친구, 비즈니스 등과 같은 그룹으로 구성할 수 있도록 하기를 원합니다.
이 새로운 기능을 구현하려면 Contact Manager 애플리케이션의 세 계층을 모두 수정해야 합니다. 컨트롤러, 서비스 계층 및 리포지토리에 새 기능을 추가해야 합니다. 코드 수정을 시작하는 즉시 이전에 작동했던 기능이 손상될 위험이 있습니다.
이전 반복에서와 같이 애플리케이션을 별도의 계층으로 리팩터링하는 것이 좋습니다. 애플리케이션의 나머지 부분을 건드리지 않고 전체 계층을 변경할 수 있기 때문에 좋은 일이었습니다. 그러나 계층 내의 코드를 더 쉽게 유지 관리하고 수정하려면 코드에 대한 단위 테스트를 만들어야 합니다.
단위 테스트를 사용하여 개별 코드 단위를 테스트합니다. 이러한 코드 단위는 전체 애플리케이션 계층보다 작습니다. 일반적으로 단위 테스트를 사용하여 코드의 특정 메서드가 예상대로 작동하는지 확인합니다. 예를 들어 ContactManagerService 클래스에서 노출하는 CreateContact() 메서드에 대한 단위 테스트를 만듭니다.
애플리케이션에 대한 단위 테스트는 안전망처럼 작동합니다. 애플리케이션에서 코드를 수정할 때마다 단위 테스트 집합을 실행하여 수정이 기존 기능을 중단하는지 여부를 검사 수 있습니다. 단위 테스트를 통해 코드를 안전하게 수정할 수 있습니다. 단위 테스트를 통해 애플리케이션의 모든 코드를 보다 복원력 있게 변경합니다.
이 반복에서는 Contact Manager 애플리케이션에 단위 테스트를 추가합니다. 이렇게 하면 다음 반복에서 기존 기능을 중단하는 것에 대해 걱정하지 않고 애플리케이션에 연락처 그룹을 추가할 수 있습니다.
참고
NUnit, xUnit.net 및 MbUnit을 비롯한 다양한 단위 테스트 프레임워크가 있습니다. 이 자습서에서는 Visual Studio에 포함된 단위 테스트 프레임워크를 사용합니다. 그러나 이러한 대체 프레임워크 중 하나를 쉽게 사용할 수 있습니다.
테스트되는 항목
완벽한 환경에서는 모든 코드가 단위 테스트로 처리됩니다. 완벽한 세상에서, 당신은 완벽한 안전망을 가질 것입니다. 애플리케이션에서 코드 줄을 수정하고 단위 테스트를 실행하여 변경 내용이 기존 기능을 손상했는지 여부를 즉시 알 수 있습니다.
그러나, 우리는 완벽한 세상에 살고 있지 않습니다. 실제로 단위 테스트를 작성할 때 비즈니스 논리(예: 유효성 검사 논리)에 대한 테스트를 작성하는 데 집중합니다. 특히 데이터 액세스 논리 또는 뷰 논리에 대한 단위 테스트를 작성 하지 않습니다 .
유용하게 사용하려면 단위 테스트를 매우 빠르게 실행해야 합니다. 애플리케이션에 대한 수백 또는 수천 개의 단위 테스트를 쉽게 누적할 수 있습니다. 단위 테스트를 실행하는 데 시간이 오래 걸리는 경우 실행하지 않습니다. 즉, 장기 실행 단위 테스트는 일상적인 코딩 목적으로는 쓸모가 없습니다.
따라서 일반적으로 데이터베이스와 상호 작용하는 코드에 대한 단위 테스트를 작성하지 않습니다. 라이브 데이터베이스에 대해 수백 개의 단위 테스트를 실행하는 것은 너무 느립니다. 대신 데이터베이스를 조롱하고 모의 데이터베이스와 상호 작용하는 코드를 작성합니다(아래 데이터베이스 모의에 대해 설명).
비슷한 이유로 일반적으로 뷰에 대한 단위 테스트를 작성하지 않습니다. 보기를 테스트하려면 웹 서버를 스핀업해야 합니다. 웹 서버를 회전하는 것은 비교적 느린 프로세스이므로 보기에 대한 단위 테스트를 만드는 것은 권장되지 않습니다.
보기에 복잡한 논리가 포함된 경우 논리를 도우미 메서드로 이동하는 것이 좋습니다. 웹 서버를 회전하지 않고 실행되는 도우미 메서드에 대한 단위 테스트를 작성할 수 있습니다.
참고
단위 테스트를 작성할 때 데이터 액세스 논리 또는 뷰 논리에 대한 테스트를 작성하는 것은 좋지 않지만 기능 또는 통합 테스트를 빌드할 때 이러한 테스트는 매우 유용할 수 있습니다.
참고
ASP.NET MVC는 Web Forms 뷰 엔진입니다. Web Forms 뷰 엔진은 웹 서버에 종속되어 있지만 다른 보기 엔진은 그렇지 않을 수 있습니다.
모의 개체 프레임워크 사용
단위 테스트를 빌드할 때 거의 항상 Mock Object 프레임워크를 활용해야 합니다. Mock Object 프레임워크를 사용하면 애플리케이션의 클래스에 대한 모의 및 스텁을 만들 수 있습니다.
예를 들어 Mock Object 프레임워크를 사용하여 리포지토리 클래스의 모의 버전을 생성할 수 있습니다. 이렇게 하면 단위 테스트에서 실제 리포지토리 클래스 대신 모의 리포지토리 클래스를 사용할 수 있습니다. 모의 리포지토리를 사용하면 단위 테스트를 실행할 때 데이터베이스 코드 실행을 방지할 수 있습니다.
Visual Studio에는 Mock Object 프레임워크가 포함되어 있지 않습니다. 그러나 .NET 프레임워크에 사용할 수 있는 몇 가지 상용 및 오픈 소스 Mock Object 프레임워크가 있습니다.
- Moq - 이 프레임워크는 오픈 소스 BSD 라이선스에서 사용할 수 있습니다. 에서 https://code.google.com/p/moq/Moq를 다운로드할 수 있습니다.
- Rhino Mocks - 이 프레임워크는 오픈 소스 BSD 라이선스에서 사용할 수 있습니다. 에서 http://ayende.com/projects/rhino-mocks.aspxRhino Mocks를 다운로드할 수 있습니다.
- Typemock 격리기 - 상업용 프레임워크입니다. 에서 http://www.typemock.com/평가판 버전을 다운로드할 수 있습니다.
이 자습서에서는 Moq를 사용하기로 결정했습니다. 그러나 Rhino Mocks 또는 Typemock Isolator를 쉽게 사용하여 Contact Manager 애플리케이션에 대한 Mock 개체를 만들 수 있습니다.
Moq를 사용하려면 다음 단계를 완료해야 합니다.
- .
- 다운로드 압축을 풀기 전에 파일을 마우스 오른쪽 단추로 클릭하고 차단 해제 라는 단추를 클릭해야 합니다(그림 1 참조).
- 다운로드 압축을 풉
- 메뉴 옵션 Project, 참조 추가를 선택하여 Moq 어셈블리에 대한 참조를 테스트 프로젝트에 추가하여 참조 추가 대화 상자를 엽니다. 찾아보기 탭에서 Moq의 압축을 푼 폴더로 이동하여 Moq.dll 어셈블리를 선택합니다. 확인 단추를 클릭합니다(그림 2 참조).
그림 01: Moq 차단 해제(전체 크기 이미지를 보려면 클릭)
그림 02: Moq를 추가한 후 참조(전체 크기 이미지를 보려면 클릭)
서비스 계층에 대한 단위 테스트 만들기
먼저 Contact Manager 애플리케이션의 서비스 계층에 대한 단위 테스트 집합을 만들어 보겠습니다. 이러한 테스트를 사용하여 유효성 검사 논리를 확인합니다.
ContactManager.Tests 프로젝트에서 Models라는 새 폴더를 만듭니다. 그런 다음 Models 폴더를 마우스 오른쪽 단추로 클릭하고 추가, 새 테스트를 선택합니다. 그림 3에 표시된 새 테스트 추가 대화 상자가 나타납니다. 단위 테스트 템플릿을 선택하고 새 테스트 이름을 ContactManagerServiceTest.vb로 지정합니다. 확인 단추를 클릭하여 테스트 프로젝트에 새 테스트를 추가합니다.
참고
일반적으로 테스트 프로젝트의 폴더 구조가 ASP.NET MVC 프로젝트의 폴더 구조와 일치하도록 합니다. 예를 들어 컨트롤러 테스트는 Controllers 폴더에, 모델 테스트는 Models 폴더에 배치합니다.
그림 03: Models\ContactManagerServiceTest.cs(전체 크기 이미지를 보려면 클릭)
처음에는 ContactManagerService 클래스에 의해 노출된 CreateContact() 메서드를 테스트하려고 합니다. 다음 5개의 테스트를 만듭니다.
- CreateContact() - 유효한 Contact가 메서드에 전달될 때 CreateContact()가 true 값을 반환하는 테스트입니다.
- CreateContactRequiredFirstName() - 이름이 누락된 Contact가 CreateContact() 메서드에 전달될 때 오류 메시지가 모델 상태에 추가되었는지 테스트합니다.
- CreateContactRequiredLastName() - 누락된 성이 있는 Contact가 CreateContact() 메서드에 전달될 때 오류 메시지가 모델 상태에 추가되었는지 테스트합니다.
- CreateContactInvalidPhone() - 잘못된 전화 번호를 가진 연락처가 CreateContact() 메서드에 전달될 때 오류 메시지가 모델 상태에 추가되도록 테스트합니다.
- CreateContactInvalidEmail() - 잘못된 전자 메일 주소를 가진 연락처가 CreateContact() 메서드에 전달될 때 오류 메시지가 모델 상태에 추가되도록 테스트합니다.
첫 번째 테스트는 유효한 연락처가 유효성 검사 오류를 생성하지 않는지 확인합니다. 나머지 테스트는 각 유효성 검사 규칙을 검사.
이러한 테스트에 대한 코드는 목록 1에 포함되어 있습니다.
목록 1 - Models\ContactManagerServiceTest.vb
Imports Microsoft.VisualStudio.TestTools.UnitTesting
Imports Moq
Imports System.Web.Mvc
<TestClass()> _
Public Class ContactManagerServiceTest
Private _mockRepository As Mock(Of IContactManagerRepository)
Private _modelState As ModelStateDictionary
Private _service As IContactManagerService
<TestInitialize()> _
Public Sub Initialize()
_mockRepository = New Mock(Of IContactManagerRepository)()
_modelState = New ModelStateDictionary()
_service = New ContactManagerService(new ModelStateWrapper(_modelState), _mockRepository.Object)
End Sub
<TestMethod()> _
Public Sub CreateContact()
' Arrange
Dim contactToCreate = Contact.CreateContact(-1, "Stephen", "Walther", "555-5555", "steve@somewhere.com")
' Act
Dim result = _service.CreateContact(contactToCreate)
' Assert
Assert.IsTrue(result)
End Sub
<TestMethod()> _
Public Sub CreateContactRequiredFirstName()
' Arrange
Dim contactToCreate = Contact.CreateContact(-1, String.Empty, "Walther", "555-5555", "steve@somewhere.com")
' Act
Dim result = _service.CreateContact(contactToCreate)
' Assert
Assert.IsFalse(result)
Dim [error] = _modelState("FirstName").Errors(0)
Assert.AreEqual("First name is required.", [error].ErrorMessage)
End Sub
<TestMethod()> _
Public Sub CreateContactRequiredLastName()
' Arrange
Dim contactToCreate = Contact.CreateContact(-1, "Stephen", String.Empty, "555-5555", "steve@somewhere.com")
' Act
Dim result = _service.CreateContact(contactToCreate)
' Assert
Assert.IsFalse(result)
Dim [error] = _modelState("LastName").Errors(0)
Assert.AreEqual("Last name is required.", [error].ErrorMessage)
End Sub
<TestMethod()> _
Public Sub CreateContactInvalidPhone()
' Arrange
Dim contactToCreate = Contact.CreateContact(-1, "Stephen", "Walther", "apple", "steve@somewhere.com")
' Act
Dim result = _service.CreateContact(contactToCreate)
' Assert
Assert.IsFalse(result)
Dim [error] = _modelState("Phone").Errors(0)
Assert.AreEqual("Invalid phone number.", [error].ErrorMessage)
End Sub
<TestMethod()> _
Public Sub CreateContactInvalidEmail()
' Arrange
Dim contactToCreate = Contact.CreateContact(-1, "Stephen", "Walther", "555-5555", "apple")
' Act
Dim result = _service.CreateContact(contactToCreate)
' Assert
Assert.IsFalse(result)
Dim [error] = _modelState("Email").Errors(0)
Assert.AreEqual("Invalid email address.", [error].ErrorMessage)
End Sub
End Class
목록 1에서 Contact 클래스를 사용하므로 테스트 프로젝트에 Microsoft Entity Framework에 대한 참조를 추가해야 합니다. System.Data.Entity 어셈블리에 대한 참조를 추가합니다.
목록 1에는 [TestInitialize] 특성으로 데코레이트된 Initialize()라는 메서드가 포함되어 있습니다. 이 메서드는 각 단위 테스트가 실행되기 전에 자동으로 호출됩니다(각 단위 테스트 직전에 5번 호출됨). Initialize() 메서드는 다음 코드 줄을 사용하여 모의 리포지토리를 만듭니다.
_mockRepository = New Mock(Of IContactManagerRepository)()
이 코드 줄은 Moq 프레임워크를 사용하여 IContactManagerRepository 인터페이스에서 모의 리포지토리를 생성합니다. 모의 리포지토리는 각 단위 테스트를 실행할 때 데이터베이스에 액세스하지 않도록 실제 EntityContactManagerRepository 대신 사용됩니다. 모의 리포지토리는 IContactManagerRepository 인터페이스의 메서드를 구현하지만 메서드는 실제로 아무 작업도 수행하지 않습니다.
참고
Moq 프레임워크를 사용하는 경우 _mockRepository 및 _mockRepository.Object를 구분합니다. 전자는 모의 리포지토리의 동작 방식을 지정하는 메서드가 포함된 Mock(Of IContactManagerRepository) 클래스를 참조합니다. 후자는 IContactManagerRepository 인터페이스를 구현하는 실제 모의 리포지토리를 나타냅니다.
모의 리포지토리는 ContactManagerService 클래스의 instance 만들 때 Initialize() 메서드에서 사용됩니다. 모든 개별 단위 테스트는 ContactManagerService 클래스의 이 instance 사용합니다.
목록 1에는 각 단위 테스트에 해당하는 5개의 메서드가 포함되어 있습니다. 이러한 각 메서드는 [TestMethod] 특성으로 데코레이트됩니다. 단위 테스트를 실행하면 이 특성이 있는 모든 메서드가 호출됩니다. 즉, [TestMethod] 특성으로 데코레이트되는 모든 메서드는 단위 테스트입니다.
CreateContact()라는 첫 번째 단위 테스트는 Contact 클래스의 유효한 instance 메서드에 전달될 때 CreateContact()를 호출하면 true 값을 반환하는지 확인합니다. 이 테스트는 Contact 클래스의 instance 만들고, CreateContact() 메서드를 호출하고, CreateContact()가 true 값을 반환하는지 확인합니다.
나머지 테스트는 CreateContact() 메서드가 잘못된 Contact를 사용하여 호출될 때 메서드가 false를 반환하고 예상 유효성 검사 오류 메시지가 모델 상태에 추가되는지 확인합니다. 예를 들어 CreateContactRequiredFirstName() 테스트는 FirstName 속성에 대한 빈 문자열을 사용하여 Contact 클래스의 instance 만듭니다. 다음으로 CreateContact() 메서드가 잘못된 Contact를 사용하여 호출됩니다. 마지막으로, 테스트는 CreateContact()가 false를 반환하고 모델 상태에 "이름 필요"라는 예상 유효성 검사 오류 메시지가 포함되어 있는지 확인합니다.
솔루션의 테스트 , 실행, 모든 테스트(Ctrl+R, A) 메뉴 옵션을 선택하여 목록 1에서 단위 테스트를 실행할 수 있습니다. 테스트 결과는 테스트 결과 창에 표시됩니다(그림 4 참조).
그림 04: 테스트 결과(전체 크기 이미지를 보려면 클릭)
컨트롤러에 대한 단위 테스트 만들기
ASP.NET MVC 애플리케이션은 사용자 상호 작용의 흐름을 제어합니다. 컨트롤러를 테스트할 때 컨트롤러가 올바른 작업 결과를 반환하고 데이터를 볼 수 있는지 테스트하려고 합니다. 컨트롤러가 예상한 방식으로 모델 클래스와 상호 작용하는지 테스트할 수도 있습니다.
예를 들어 목록 2에는 Contact 컨트롤러 Create() 메서드에 대한 두 가지 단위 테스트가 포함되어 있습니다. 첫 번째 단위 테스트는 유효한 Contact가 Create() 메서드에 전달되면 Create() 메서드가 인덱스 작업으로 리디렉션되는지 확인합니다. 즉, 유효한 Contact를 전달하면 Create() 메서드는 Index 작업을 나타내는 RedirectToRouteResult를 반환해야 합니다.
컨트롤러 계층을 테스트할 때 ContactManager 서비스 계층을 테스트하지 않습니다. 따라서 Initialize 메서드에서 다음 코드를 사용하여 서비스 계층을 모의합니다.
_service = New Mock(Of IContactManagerService)()
CreateValidContact() 단위 테스트에서 다음 코드 줄을 사용하여 서비스 계층 CreateContact() 메서드를 호출하는 동작을 모의합니다.
_service.Expect( Function(s) s.CreateContact(contactToCreate) ).Returns(True)
이 코드 줄은 CreateContact() 메서드가 호출되면 모의 ContactManager 서비스가 true 값을 반환하도록 합니다. 서비스 계층을 모의하여 서비스 계층에서 코드를 실행할 필요 없이 컨트롤러의 동작을 테스트할 수 있습니다.
두 번째 단위 테스트는 잘못된 연락처가 메서드에 전달될 때 Create() 작업이 만들기 뷰를 반환하는지 확인합니다. 서비스 계층 CreateContact() 메서드가 다음 코드 줄과 함께 false 값을 반환하도록 합니다.
_service.Expect( Function(s) s.CreateContact(contactToCreate) ).Returns(False)
Create() 메서드가 예상대로 동작하는 경우 서비스 계층이 false 값을 반환할 때 Create 뷰를 반환해야 합니다. 이렇게 하면 컨트롤러가 만들기 보기에 유효성 검사 오류 메시지를 표시할 수 있으며 사용자는 잘못된 연락처 속성을 수정할 수 있습니다.
컨트롤러에 대한 단위 테스트를 빌드하려는 경우 컨트롤러 작업에서 명시적 보기 이름을 반환해야 합니다. 예를 들어 다음과 같은 뷰를 반환하지 마세요.
Return View()
대신 다음과 같이 보기를 반환합니다.
반환 뷰("Create")
뷰를 반환할 때 명시적이지 않은 경우 ViewResult.ViewName 속성은 빈 문자열을 반환합니다.
목록 2 - Controllers\ContactControllerTest.vb
Imports Microsoft.VisualStudio.TestTools.UnitTesting
Imports Moq
Imports System.Web.Mvc
<TestClass()> _
Public Class ContactControllerTest
Private _service As Mock(Of IContactManagerService)
<TestInitialize()> _
Public Sub Initialize()
_service = New Mock(Of IContactManagerService)()
End Sub
<TestMethod()> _
Public Sub CreateValidContact()
' Arrange
Dim contactToCreate = New Contact()
_service.Expect(Function(s) s.CreateContact(contactToCreate)).Returns(True)
Dim controller = New ContactController(_service.Object)
' Act
Dim result = CType(controller.Create(contactToCreate), RedirectToRouteResult)
' Assert
Assert.AreEqual("Index", result.RouteValues("action"))
End Sub
<TestMethod()> _
Public Sub CreateInvalidContact()
' Arrange
Dim contactToCreate = New Contact()
_service.Expect(Function(s) s.CreateContact(contactToCreate)).Returns(False)
Dim controller = New ContactController(_service.Object)
' Act
Dim result = CType(controller.Create(contactToCreate), ViewResult)
' Assert
Assert.AreEqual("Create", result.ViewName)
End Sub
End Class
요약
이 반복에서는 Contact Manager 애플리케이션에 대한 단위 테스트를 만들었습니다. 언제든지 이러한 단위 테스트를 실행하여 애플리케이션이 예상대로 작동하는지 확인할 수 있습니다. 단위 테스트는 향후 애플리케이션을 안전하게 수정할 수 있도록 애플리케이션의 안전망 역할을 합니다.
두 개의 단위 테스트 집합을 만들었습니다. 먼저 서비스 계층에 대한 단위 테스트를 만들어 유효성 검사 논리를 테스트했습니다. 다음으로 컨트롤러 계층에 대한 단위 테스트를 만들어 흐름 제어 논리를 테스트했습니다. 서비스 계층을 테스트할 때 리포지토리 계층을 모의하여 리포지토리 계층에서 서비스 계층에 대한 테스트를 격리했습니다. 컨트롤러 계층을 테스트할 때 서비스 계층을 모의하여 컨트롤러 계층에 대한 테스트를 격리했습니다.
다음 반복에서는 연락처 그룹을 지원하게 Contact Manager 애플리케이션을 수정합니다. 테스트 기반 개발이라는 소프트웨어 디자인 프로세스를 사용하여 이 새로운 기능을 애플리케이션에 추가합니다.