연습: 관리 코드에 대한 단위 테스트 만들기 및 실행Walkthrough: Creating and Running Unit Tests for Managed Code

이 연습에서는 관리 코드에 대한 Microsoft 단위 테스트 프레임워크 및 Visual Studio 테스트 탐색기를 사용하여 일련의 단위 테스트를 생성, 실행 및 사용자 지정하는 방법을 안내합니다.This walkthrough will step you through creating, running, and customizing a series of unit tests using the Microsoft unit test framework for managed code and the Visual Studio Test Explorer. 개발 중인 C# 프로젝트로 시작하여 해당 코드를 실행해 보는 테스트를 만들어 테스트를 실행하고 결과를 검사합니다.You start with a C# project that is under development, create tests that exercise its code, run the tests, and examine the results. 그런 다음 프로젝트 코드를 변경하고 테스트를 다시 실행할 수 있습니다.Then you can change your project code and re-run the tests.

이 항목에는 다음과 같은 단원이 포함되어 있습니다.This topic contains the following sections:

연습 준비Prepare the walkthrough

단위 테스트 프로젝트 만들기Create a unit test project

테스트 클래스 만들기Create the test class

참고

이 연습에서는 관리 코드에 Microsoft 단위 테스트 프레임워크를 사용합니다.This walkthrough uses the Microsoft unit test framework for managed code. 테스트 탐색기에서는 테스트 탐색기용 어댑터가 포함된 타사 단위 테스트 프레임워크의 테스트도 실행할 수 있습니다.Test Explorer also can run tests from third party unit test frameworks that have adapters for Test Explorer. 자세한 내용은 타사 단위 테스트 프레임워크 설치를 참조하세요.For more information, see Install third-party unit test frameworks

참고

명령줄에서 테스트를 실행하는 방법에 대한 자세한 내용은 연습: 명령줄 테스트 유틸리티 사용을 참조하세요.For information about how to run tests from a command line, see Walkthrough: using the command-line test utility.

필수 구성 요소Prerequisites

연습 준비Prepare the walkthrough

  1. Visual Studio를 엽니다.Open Visual Studio.

  2. 파일 메뉴에서 새로 만들기 를 가리킨 다음 프로젝트를 클릭합니다.On the File menu, point to New and then click Project.

    새 프로젝트 대화 상자가 나타납니다.The New Project dialog box appears.

  3. 설치된 템플릿에서 Visual C#을 클릭합니다.Under Installed Templates, click Visual C#.

  4. 응용 프로그램 형식 목록에서 클래스 라이브러리를 클릭합니다.In the list of application types, click Class Library.

  5. In the 이름 상자에 Bank 를 가리킨 다음 확인을 참조하세요.In the Name box, type Bank and then click OK.

    참고

    "Bank"라는 이름이 이미 사용되고 있으면 프로젝트에 대해 다른 이름을 선택합니다.If the name "Bank" is already used, choose another name for the project.

    새 Bank 프로젝트가 만들어져 솔루션 탐색기에 표시되고 코드 편집기에 Class1.cs 파일이 열립니다.The new Bank project is created and displayed in Solution Explorer with the Class1.cs file open in the Code Editor.

    참고

    Class1.cs 파일이 코드 편집기에서 열리지 않으면 솔루션 탐색기에서 Class1.cs 파일을 두 번 클릭하여 엽니다.If the Class1.cs file is not open in the Code Editor, double-click the file Class1.cs in Solution Explorer to open it.

  6. 단위 테스트를 만들기 위한 샘플 프로젝트에서 소스 코드를 복사합니다.Copy the source code from the Sample Project for Creating Unit Tests.

  7. Class1.cs의 원래 내용을 단위 테스트를 만들기 위한 샘플 프로젝트의 코드로 바꿉니다.Replace the original contents of Class1.cs with the code from the Sample Project for Creating Unit Tests.

  8. 파일을 BankAccount.cs로 저장합니다.Save the file as BankAccount.cs

  9. 빌드 메뉴에서 솔루션 빌드를 클릭합니다.On the Build menu, click Build Solution.

    이제 Bank라는 프로젝트가 준비되었습니다.You now have a project named Bank. 이 프로젝트에는 테스트할 소스 코드와 테스트에 사용할 도구가 들어 있습니다.It contains source code to test and tools to test it with. Bank에 대한 네임스페이스 BankAccountNS에는 다음 절차에서 테스트할 메서드가 포함된 공용 클래스인 BankAccount가 있습니다.The namespace for Bank, BankAccountNS, contains the public class BankAccount, whose methods you will test in the following procedures.

    신속한 시작으로 사용자는 Debit 메서드에 집중합니다. 현금 인출 시 Debit 메서드가 호출되며 다음 코드가 포함됩니다.In this quick start, we focus on the Debit method.The Debit method is called when money is withdrawn an account and contains the following code:

// method under test  
public void Debit(double amount)  
{  
    if(amount > m_balance)  
    {  
        throw new ArgumentOutOfRangeException("amount");  
    }  
    if (amount < 0)  
    {  
        throw new ArgumentOutOfRangeException("amount");  
    }  
    m_balance += amount;  
}  

단위 테스트 프로젝트 만들기Create a unit test project

필수 조건: Prepare the walkthrough절차의 단계를 따릅니다.Prerequisite: Follow the steps in the procedure, Prepare the walkthrough.

단위 테스트 프로젝트를 만들려면To create a unit test project

  1. 파일 메뉴에서 추가를 선택한 다음 새 프로젝트...를 선택합니다.On the File menu, choose Add, and then choose New Project ....

  2. 새 프로젝트 대화 상자에서 설치됨, Visual C#을 확장한 다음 테스트를 선택합니다.In the New Project dialog box, expand Installed, expand Visual C#, and then choose Test.

  3. 템플릿 목록에서 단위 테스트 프로젝트를 선택합니다.From the list of templates, select Unit Test Project.

  4. 이름 상자에 BankTest를 입력한 다음 확인을 선택합니다.In the Name box, enter BankTest, and then choose OK.

    BankTests 프로젝트가 Bank 솔루션에 추가됩니다.The BankTests project is added to the the Bank solution.

  5. BankTests 프로젝트에서 Bank 솔루션에 대한 참조를 추가합니다.In the BankTests project, add a reference to the Bank solution.

    솔루션 탐색기에서 BankTests 프로젝트의 참조 를 선택하고 상황에 맞는 메뉴에서 참조 추가... 를 선택합니다.In Solution Explorer, select References in the BankTests project and then choose Add Reference... from the context menu.

  6. 참조 관리자 대화 상자에서 솔루션 을 확장한 다음 Bank 항목을 선택합니다.In the Reference Manager dialog box, expand Solution and then check the Bank item.

테스트 클래스 만들기Create the test class

BankAccount 클래스를 확인하려면 테스트 클래스가 필요합니다.We need a test class for verifying the BankAccount class. 프로젝트 템플릿에서 생성된 UnitTest1.cs를 사용할 수 있지만 파일 및 클래스에 설명이 포함된 이름을 제공해야 합니다.We can use the UnitTest1.cs that was generated by the project template, but we should give the file and class more descriptive names. 솔루션 탐색기에서 파일 이름을 바꾸면 한 번에 수행할 수 있습니다.We can do that in one step by renaming the file in Solution Explorer.

클래스 파일 이름 변경Renaming a class file

솔루션 탐색기에서 BankTests 프로젝트의 UnitTest1.cs 파일을 선택합니다.In Solution Explorer, select the UnitTest1.cs file in the BankTests project. 상황에 맞는 메뉴에서 이름 바꾸기를 선택한 다음 파일 이름을 BankAccountTests.cs로 바꿉니다.From the context menu, choose Rename, and then rename the file to BankAccountTests.cs. 프로젝트의 모든 참조 이름을 코드 요소 'UnitTest1'로 바꿀지 묻는 대화 상자에서 를 선택합니다.Choose Yes on the dialog that asks if you want to rename all references in the project to the code element 'UnitTest1'. 이 단계에서는 클래스 이름을 BankAccountTest로 변경합니다.This step changes the name of the class to BankAccountTest.

BankAccountTests.cs 파일에는 이제 다음 코드가 들어 있습니다.The BankAccountTests.cs file now contains the following code:

// unit test code  
using System;  
using Microsoft.VisualStudio.TestTools.UnitTesting;  

namespace BankTests  
{  
    [TestClass]  
    public class BankAccountTests  
    {  
        [TestMethod]  
        public void TestMethod1()  
        {  
        }  
    }  
}  

테스트에서 프로젝트에 using 문 추가Add a using statement to the project under test

using 문을 클래스에 추가하여 정규화된 이름을 사용하지 않고 테스트 중인 프로젝트를 호출할 수 있습니다.We can also add a using statement to the class to let us to call into the project under test without using fully qualified names. 클래스 파일의 맨 위에 다음을 추가합니다.At the top of the class file, add:

using BankAccountNS;  

테스트 클래스 요구 사항Test class requirements

테스트 클래스의 최소 요구 사항은 다음과 같습니다.The minimum requirements for a test class are the following:

  • [TestClass] 특성은 테스트 탐색기에서 실행하려는 단위 테스트 메서드가 포함된 모든 클래스의 관리 코드에 대한 Microsoft 단위 테스트 프레임워크에 필요합니다.The [TestClass] attribute is required in the Microsoft unit testing framework for managed code for any class that contains unit test methods that you want to run in Test Explorer.

  • 테스트 탐색기에서 실행하려는 각 테스트 메서드에는 [TestMethod]특성이 있어야 합니다.Each test method that you want Test Explorer to run must have the [TestMethod]attribute.

    [TestClass] 특성이 없는 단위 테스트 프로젝트에 다른 클래스를 사용하거나 [TestMethod] 특성이 없는 테스트 클래스에 다른 메서드를 사용할 수 있습니다.You can have other classes in a unit test project that do not have the [TestClass] attribute, and you can have other methods in test classes that do not have the [TestMethod] attribute. 테스트 메서드에서 이러한 다른 클래스와 메서드를 사용할 수 있습니다.You can use these other classes and methods in your test methods.

첫 번째 테스트 메서드 만들기Create the first test method

이 절차에서는 단위 테스트 메서드를 작성하여 Debit 클래스의 BankAccount 메서드 동작을 확인합니다.In this procedure, we will write unit test methods to verify the behavior of the Debit method of the BankAccount class. 이 메서드가 위에 나열되어 있습니다.The method is listed above.

테스트 중인 메서드를 분석한 결과, 세 가지 이상의 동작을 확인하기로 결정했습니다.By analyzing the method under test, we determine that there are at least three behaviors that need to be checked:

  1. 이 메서드는 대변 금액이 잔액보다 큰 경우 ArgumentOutOfRangeException 을 발생시킵니다.The method throws an ArgumentOutOfRangeException if the debit amount is greater than the balance.

  2. 또한 대변 금액이 0보다 작을 경우에도 ArgumentOutOfRangeException 을 발생시킵니다.It also throws ArgumentOutOfRangeException if the debit amount is less than zero.

  3. 1)과 2)의 검사가 충족될 경우 이 메서드는 계정 잔액에서 금액을 뺍니다.If the checks in 1.) and 2.) are satisfied, the method subtracts the amount from the account balance.

    첫 번째 테스트에서는 유효 금액(계정 잔액보다 작고 0보다 큰 값)이 계정으로부터 올바른 금액을 인출하는지 확인합니다.In our first test, we verify that a valid amount (one that is less than the account balance and that is greater than zero) withdraws the correct amount from the account.

테스트 메서드를 만들려면To create a test method

  1. using BankAccountNS; 문을 BankAccountTests.cs 파일에 추가합니다.Add a using BankAccountNS; statement to the BankAccountTests.cs file.

  2. 다음 메서드를 BankAccountTests 클래스에 추가합니다.Add the following method to that BankAccountTests class:

    // unit test code  
    [TestMethod]  
    public void Debit_WithValidAmount_UpdatesBalance()  
    {  
        // arrange  
        double beginningBalance = 11.99;  
        double debitAmount = 4.55;  
        double expected = 7.44;  
        BankAccount account = new BankAccount("Mr. Bryan Walton", beginningBalance);  
    
        // act  
        account.Debit(debitAmount);  
    
        // assert  
        double actual = account.Balance;  
        Assert.AreEqual(expected, actual, 0.001, "Account not debited correctly");  
    }  
    

    이 메서드는 상당히 간단합니다.The method is rather simple. 기초 잔액으로 새 BankAccount 개체를 만든 다음 유효한 금액을 인출합니다.We set up a new BankAccount object with a beginning balance and then withdraw a valid amount. 관리 코드 <xref:Microsoft.VisualStudio.TestTools.UnitTesting.Assert.AreEqual%2A> 메서드에 Microsoft 단위 테스트 프레임워크를 사용하여 마감 잔액이 기대한 것과 같은지 확인합니다.We use the Microsoft unit test framework for managed code <xref:Microsoft.VisualStudio.TestTools.UnitTesting.Assert.AreEqual%2A> method to verify that the ending balance is what we expect.

테스트 메서드 요구 사항Test method requirements

테스트 메서드는 다음 요구 사항을 충족해야 합니다.A test method must meet the following requirements:

  • 이 메서드를 [TestMethod] 특성으로 데코레이팅해야 합니다.The method must be decorated with the [TestMethod] attribute.

  • 이 메서드는 void를 반환해야 합니다.The method must return void.

  • 메서드에 매개 변수를 사용할 수 없습니다.The method cannot have parameters.

테스트 빌드 및 실행Build and run the test

테스트를 빌드 및 실행하려면To build and run the test

  1. 빌드 메뉴에서 솔루션 빌드를 선택합니다.On the Build menu, choose Build Solution.

    오류가 없는 경우 실행하지 않은 테스트 그룹에 나열된 Debit_WithValidAmount_UpdatesBalance 와 함께 UnitTestExplorer 창이 나타납니다.If there are no errors, the UnitTestExplorer window appears with Debit_WithValidAmount_UpdatesBalance listed in the Not Run Tests group. 빌드에 성공한 후 테스트 탐색기가 나타나지 않는 경우 메뉴에서 테스트 를 선택하고, 을 선택한 다음 테스트 탐색기를 선택합니다.If Test Explorer does not appear after a successful build, choose Test on the menu, then choose Windows, and then choose Test Explorer.

  2. 모두 실행 을 선택하여 테스트를 실행합니다.Choose Run All to run the test. 테스트가 실행되는 동안 창 맨 위의 상태 표시줄에 애니메이션이 사용됩니다.As the test is running the status bar at the top of the window is animated. 테스트 실행이 끝날 때 테스트 메서드가 통과했으면 녹색이 되고 테스트가 실패하면 빨간색이 됩니다.At the end of the test run, the bar turns green if all the test methods pass, or red if any of the tests fail.

  3. 이러한 경우 테스트가 실패할 수 있습니다.In this case, the test does fail. 테스트 메서드가 실패한 테스트그룹으로The test method is moved to the Failed Tests. 와 함께 UnitTestExplorer 창이 나타납니다.group. 창 하단에서 세부 정보를 보려면 테스트 탐색기에서 메서드를 선택합니다.Select the method in Test Explorer to view the details at the bottom of the window.

코드를 수정하고 테스트 다시 실행Fix your code and rerun your tests

테스트 결과 분석Analyze the test results

테스트 결과에 실패를 설명하는 메시지가 포함됩니다.The test result contains a message that describes the failure. AreEquals 메서드의 경우 메시지에 예상 값(Expected<XXX> **매개 변수)과 실제 값(Actual<YYY>** 매개 변수)이 표시됩니다.For the AreEquals method, message displays you what was expected (the (Expected<XXX>parameter) and what was actually received (the Actual<YYY> parameter). 기초 잔액보다 줄어든 잔액을 예상했지만, 인출액만큼 늘어났습니다.We were expecting the balance to decline from the beginning balance, but instead it has increased by the amount of the withdrawal.

다시 검사한 Debit 코드에 단위 테스트를 통해 버그를 찾는 데 성공한 것으로 나타납니다.A reexamination of the Debit code shows that the unit test has succeeded in finding a bug. 차감해야 할 경우 계정 잔액에 인출금이 추가됩니다.The amount of the withdrawal is added to the account balance when it should be subtracted.

버그 수정Correct the bug

오류를 수정하려면 다음 줄To correct the error, simply replace the line

m_balance += amount;  

을(를) 다음으로 바꾸면 됩니다.with

m_balance -= amount;  

테스트 다시 실행Rerun the test

테스트 탐색기에서 모두 실행 을 선택하여 테스트를 다시 실행합니다.In Test Explorer, choose Run All to rerun the test. 빨강/녹색 막대가 녹색으로 바뀌고 테스트는 통과한 테스트 그룹으로 이동합니다.The red/green bar turns green, and the test is moved to the Passed Tests group.

단위 테스트를 사용하여 코드 개선Use unit tests to improve your code

이 섹션에서는 반복적인 분석 프로세스, 단위 테스트 개발 및 리팩터링을 통해 프로덕션 코드를 보다 강력하고 효과적으로 만드는 방법을 설명합니다.This section describes how an iterative process of analysis, unit test development, and refactoring can help you make your production code more robust and effective.

문제 분석Analyze the issues

테스트 메서드를 만들어 Debit 메서드에서 유효한 금액이 정확하게 차감된 것을 확인한 후에는 원래 분석의 나머지 사례를 살펴볼 수 있습니다.After creating a test method to confirm that a valid amount is correctly deducted in the Debit method, we can turn to remaining cases in our original analysis:

  1. 이 메서드는 대변 금액이 잔액보다 큰 경우 ArgumentOutOfRangeException 을 발생시킵니다.The method throws an ArgumentOutOfRangeException if the debit amount is greater than the balance.

  2. 또한 대변 금액이 0보다 작을 경우에도 ArgumentOutOfRangeException 을 발생시킵니다.It also throws ArgumentOutOfRangeException if the debit amount is less than zero.

    테스트 메서드 만들기Create the test methods

    테스트 메서드를 만들어 이러한 문제를 해결하려는 첫 번째 시도가 성공할 가능성이 높습니다.A first attempt at creating a test method to address these issues seems promising:

//unit test method  
[TestMethod]  
[ExpectedException(typeof(ArgumentOutOfRangeException))]  
public void Debit_WhenAmountIsLessThanZero_ShouldThrowArgumentOutOfRange()  
{  
    // arrange  
    double beginningBalance = 11.99;  
    double debitAmount = -100.00;  
    BankAccount account = new BankAccount("Mr. Bryan Walton", beginningBalance);  

    // act  
    account.Debit(debitAmount);  

    // assert is handled by ExpectedException  
}  

<xref:Microsoft.VisualStudio.TestTools.UnitTesting.ExpectedExceptionAttribute> 특성을 사용하여 올바른 예외가 throw되었음을 어설션합니다.We use the <xref:Microsoft.VisualStudio.TestTools.UnitTesting.ExpectedExceptionAttribute> attribute to assert that the right exception has been thrown. ArgumentOutOfRangeException 을 throw되는 경우가 아니면 이 특성으로 인해 테스트에 실패합니다.The attribute causes the test to fail unless an ArgumentOutOfRangeException is thrown. 양수 및 음수 debitAmount 값을 모두 사용하여 테스트를 실행한 후 금액이 0보다 작은 경우 제네릭 ApplicationException 을 throw하는 테스트를 위해 메서드를 일시적으로 수정하면 테스트가 올바르게 작동함을 알 수 있습니다.Running the test with both positive and negative debitAmount values and then temporarily modifying the method under test to throw a generic ApplicationException when the amount is less than zero demonstrates that test behaves correctly. 인출한 금액이 잔액보다 많을 경우를 테스트하려면 다음을 수행해야 합니다.To test the case when the amount withdrawn is greater than the balance, all we need to do is:

  1. Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange라는 새 테스트 메서드를 만듭니다.Create a new test method named Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange.

  2. Debit_WhenAmountIsLessThanZero_ShouldThrowArgumentOutOfRange 의 메서드 본문을 새 메서드로 복사합니다.Copy the method body from Debit_WhenAmountIsLessThanZero_ShouldThrowArgumentOutOfRange to the new method.

  3. debitAmount 를 잔액보다 큰 값으로 설정합니다.Set the debitAmount to a number greater than the balance.

    테스트 실행Run the tests

    debitAmount 에 대한 값이 서로 다른 두 메서드를 실행하여 테스트에서 나머지 경우가 적절히 처리되는지 확인할 수 있습니다.Running the two methods with different values for debitAmount demonstrates that the tests adequately handle our remaining cases. 세 테스트를 모두 실행하면 원래 분석의 모든 경우가 올바르게 검사되는지 확인할 수 있습니다.Running all three tests confirm that all cases in our original analysis are correctly covered.

    분석 계속 수행Continue the analysis

    하지만 마지막 두 테스트 메서드는 다소 문제가 있습니다.However, the last two test methods are also somewhat troubling. 각 테스트를 실행할 때 테스트 중인 코드의 어떤 조건이 throw되는지 확실히 알 수 없습니다.We cannot be certain which condition in the code under test throws when either test runs. 두 조건을 구분하는 몇 가지 방법이 유용합니다.Some way of differentiating the two conditions would be helpful. 즉, 위반한 조건을 확실히 알면 테스트에 대한 자신감이 증가합니다.As we think about the problem more, it becomes apparent that knowing which condition was violated would increase our confidence in the tests. 이 정보는 테스트 중인 메서드에 의해 throw되는 예외를 처리하는 프로덕션 메커니즘에도 유용할 것입니다.This information would also very likely be helpful to the production mechanism that handles the exception when it is thrown by the method under test. 메서드가 throw할 때 자세한 정보가 생성되면 관련된 모든 문제에 도움이 되지만 ExpectedException 특성은 이 정보를 제공할 수 없습니다.Generating more information when the method throws would assist all concerned, but the ExpectedException attribute cannot supply this information..

    테스트 중인 메서드를 살펴보면 인수 이름을 매개 변수로 받는 ArgumentOutOfRangeException 생성자가 두 조건문 모두에 사용된다는 사실을 알 수 있습니다.Looking at the method under test again, we see both conditional statements use an ArgumentOutOfRangeException constructor that takes name of the argument as a parameter:

throw new ArgumentOutOfRangeException("amount");  

MSDN 라이브러리를 검색하면 많은 정보를 제공하는 생성자가 있음을 알 수 있습니다.From a search of the MSDN Library, we discover that a constructor exists that reports far richer information. ArgumentOutOfRangeException(String, Object, String) 에는 인수 이름, 인수 값 및 사용자 정의 메시지가 포함됩니다.ArgumentOutOfRangeException(String, Object, String) includes the name of the argument, the argument value, and a user-defined message. 이 생성자를 사용하도록 테스트 중인 메서드를 리팩터링할 수 있습니다.We can refactor the method under test to use this constructor. 더 좋은 점은 공개적으로 사용할 수 있는 형식 멤버를 사용하여 오류를 지정할 수 있다는 점입니다.Even better, we can use publicly available type members to specify the errors.

테스트 중인 코드 리팩터링Refactor the code under test

먼저 클래스 범위에서 오류 메시지에 대한 두 개 상수를 정의합니다.We first define two constants for the error messages at class scope:

// class under test  
public const string DebitAmountExceedsBalanceMessage = "Debit amount exceeds balance";  
public const string DebitAmountLessThanZeroMessage = "Debit amount less than zero";  

그런 다음 Debit 메서드에서 두 조건문을 수정합니다.We then modify the two conditional statements in the Debit method:

// method under test  
// ...  
    if (amount > m_balance)  
    {  
        throw new ArgumentOutOfRangeException("amount", amount, DebitAmountExceedsBalanceMessage);  
    }  

    if (amount < 0)  
    {  
        throw new ArgumentOutOfRangeException("amount", amount, DebitAmountLessThanZeroMessage);  
    }  
// ...  

테스트 메서드 리팩터링Refactor the test methods

테스트 메서드에서 먼저 ExpectedException 특성을 제거합니다.In our test method, we first remove the ExpectedException attribute. 해당 위치에서 throw된 예외를 catch하고 올바른 조건 문에서 throw되었는지 확인합니다.In its place, we catch the thrown exception and verify that it was thrown in the correct condition statement. 그러나 두 옵션 중 하나를 결정하여 나머지 조건을 확인해야 합니다.However, we must now decide between two options to verify our remaining conditions. 예를 들어, Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange 메서드에서 다음 중 한 가지 작업을 수행할 수 있습니다.For example in the Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange method, we can take one of the following actions:

  • 예외의 ActualValue 속성( ArgumentOutOfRangeException 생성자의 두 번째 매개 변수)이 기초 잔액보다 크다고 어셜션합니다.Assert that the ActualValue property of the exception (the second parameter of the ArgumentOutOfRangeException constructor) is greater than the beginning balance. 이 옵션을 사용하려면 테스트 메서드의 ActualValue 변수에 대해 예외의 beginningBalance 속성을 테스트해야 하고, ActualValue 가 0보다 큰지도 확인해야 합니다.This option requires that we test the ActualValue property of the exception against the beginningBalance variable of the test method, and also requires then verify that the ActualValue is greater than zero.

  • 메시지(생성자의 세 번째 매개 변수)에 DebitAmountExceedsBalanceMessageBankAccount 클래스에 정의되어 있음을 어셜션합니다.Assert that the message (the third parameter of the constructor) includes the DebitAmountExceedsBalanceMessage defined in the BankAccount class.

    Microsoft 단위 테스트 프레임워크에서 <xref:Microsoft.VisualStudio.TestTools.UnitTesting.StringAssert.Contains%2A?displayProperty=fullName> 메서드를 사용하면 첫 번째 옵션에서 필요한 계산 없이도 두 번째 옵션을 확인할 수 있습니다.The <xref:Microsoft.VisualStudio.TestTools.UnitTesting.StringAssert.Contains%2A?displayProperty=fullName> method in the Microsoft unit test framework enables us to verify the second option without the calculations that are required of the first option.

    Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange 를 수정하는 두 번째 시도의 예를 들면 다음과 같습니다.A second attempt at revising Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange might look like:

[TestMethod]  
public void Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange()  
{  
    // arrange  
    double beginningBalance = 11.99;  
    double debitAmount = 20.0;  
    BankAccount account = new BankAccount("Mr. Bryan Walton", beginningBalance);  

    // act  
    try  
    {  
        account.Debit(debitAmount);  
    }  
    catch (ArgumentOutOfRangeException e)  
    {  
        // assert  
        StringAssert.Contains(e.Message, BankAccount. DebitAmountExceedsBalanceMessage);  
    }  
}  

재테스트, 재작성 및 재분석Retest, rewrite, and reanalyze

테스트 메서드를 다른 값으로 다시 테스트하면 다음과 같은 사실이 발생합니다.When we retest the test methods with different values, we encounter the following facts:

  1. debitAmount 가 잔액보다 큰 어설션을 사용하여 올바른 오류를 catch하는 경우 Contains 어설션이 통과하고, 예외가 무시되어 테스트 메서드를 통과하게 됩니다.If we catch the correct error by using an assert where debitAmount that is greater than the balance, the Contains assert passes, the exception is ignored, and so the test method passes. 이것이 바로 우리가 원하는 동작입니다.This is the behavior we want.

  2. 0보다 작은 debitAmount 를 사용할 경우 잘못된 오류 메시지가 반환되어 어설션이 실패합니다.If we use a debitAmount that is less than 0, the assert fails because the wrong error message is returned. 테스트 코드 경로 아래 메서드의 다른 지점에서 임시 ArgumentOutOfRange 예외를 유도하는 경우에도 어설션이 실패합니다.The assert also fails if we introduce a temporary ArgumentOutOfRange exception at another point in the method under test code path. 이 점 역시 좋습니다.This too is good.

  3. debitAmount 값이 유효하면(예: 잔액보다 작지만 0보다 큼) 예외가 catch되지 않으므로 어설션이 절대로 catch되지 않습니다.If the debitAmount value is valid (i.e., less than the balance but greater than zero, no exception is caught, so the assert is never caught. 테스트 메서드를 통과합니다.The test method passes. 예외가 throw되지 않는 경우에도 테스트 메서드가 실패하지 않아야 하므로 이 방법은 좋지 않습니다.This is not good, because we want the test method to fail if no exception is thrown.

    세 번째 사실은 테스트 메서드의 버그입니다.The third fact is a bug in our test method. 여기서는 문제를 해결하기 위해 테스트 메서드 끝에 예외가 throw되지 않은 경우를 처리하도록 <xref:Microsoft.VisualStudio.TestTools.UnitTesting.Assert.Fail%2A> 어설션을 추가합니다.To attempt to resolve the issue, we add a <xref:Microsoft.VisualStudio.TestTools.UnitTesting.Assert.Fail%2A> assert at the end of the test method to handle the case where no exception is thrown.

    하지만 재테스트를 통해 올바른 예외가 catch되면 테스트가 실패한다는 점이 확인되었습니다.But retesting shows that the test now fails if the correct exception is caught. catch 문이 예외를 다시 설정하고 메서드가 계속 실행되어 새 어설션에서 실패합니다.The catch statement resets the exception and the method continues to execute, failing at the new assert. 새 문제를 해결하기 위해 return 다음에 StringAssert문을 추가합니다.To resolve the new problem, we add a return statement after the StringAssert. 재테스트를 통해 문제를 해결한 것을 확인합니다.Retesting confirms that we have fixed our problems. Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange 의 최종 버전은 다음과 같습니다.Our final version of the Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange looks like the following:

[TestMethod]  
public void Debit_WhenAmountIsMoreThanBalance_ShouldThrowArgumentOutOfRange()  
{  
    // arrange  
    double beginningBalance = 11.99;  
    double debitAmount = 20.0;  
    BankAccount account = new BankAccount("Mr. Bryan Walton", beginningBalance);  

    // act  
    try  
    {  
        account.Debit(debitAmount);  
    }  
    catch (ArgumentOutOfRangeException e)  
    {  
        // assert  
        StringAssert.Contains(e.Message, BankAccount. DebitAmountExceedsBalanceMessage);  
        return;  
    }  
    Assert.Fail("No exception was thrown.");  
}  

이 최종 단원에서는 테스트 코드 개선 작업으로 테스트 메서드가 더욱 더 견고하고 유용해졌습니다.In this final section, the work that we did improving our test code led to more robust and informative test methods. 하지만 더 중요한 것은 추가 분석을 통해 테스트 중인 프로젝트의 코드가 향상되었다는 점입니다.But more importantly, the extra analysis also led to better code in our project under test.