Microsoft Fakes를 사용하여 테스트 중인 코드 격리Isolating Code Under Test with Microsoft Fakes

Microsoft Fakes는 스텁 또는 shim을 사용하는 응용 프로그램의 다른 부분을 교체함으로써 사용자가 테스트 중인 코드를 격리시켜 줍니다.Microsoft Fakes help you isolate the code you are testing by replacing other parts of the application with stubs or shims. 테스트에서 제어하는 작은 코드 조각입니다.These are small pieces of code that are under the control of your tests. 테스트를 위해 코드를 격리하여 테스트가 실패할 경우 원인이 어디에 있는지 파악합니다.By isolating your code for testing, you know that if the test fails, the cause is there and not somewhere else. 응용 프로그램의 다른 부분이 아직 작동하지 않더라도 스텁 및 shim을 사용해서 코드를 테스트할 수도 있습니다.Stubs and shims also let you test your code even if other parts of your application are not working yet.

Fakes는 두 가지 버전이 있습니다.Fakes come in two flavors:

  • 스텁은 클래스를 동일한 인터페이스를 구현하는 작은 대안으로 바뀝니다.A stub replaces a class with a small substitute that implements the same interface. 스텁을 사용하려면 각 구성 요소가 다른 구성 요소에 종속되는 것이 아니라 인터페이스에만 종속되도록 응용 프로그램을 설계해야 합니다.To use stubs, you have to design your application so that each component depends only on interfaces, and not on other components. ("구성 요소"란 함께 설계되어 업데이트되고 대개 하나의 어셈블리에 포함되는 클래스 또는 클래스의 그룹을 의미합니다.)(By "component" we mean a class or group of classes that are designed and updated together and typically contained in an assembly.)

  • shim은 지정된 메서드 콜을 실행하는 대신 테스트에서 제공하는 shim 코드를 실행할 수 있도록 런타임에 응용 프로그램의 컴파일된 코드를 수정합니다.A shim modifies the compiled code of your application at run time so that instead of making a specified method call, it runs the shim code that your test provides. shim은 .NET 어셈블리와 같이 수정할 수 없는 어셈블리에 대한 호출을 바꾸는 데 사용할 수 있습니다.Shims can be used to replace calls to assemblies that you cannot modify, such as .NET assemblies.

    다른 구성 요소를 대체하는 FakesFakes replace other components

    RequirementsRequirements

  • Visual Studio EnterpriseVisual Studio Enterprise

스텁 및 shim 형식 중에 선택Choosing between stub and shim types

일반적으로 이러한 클래스를 동시에 개발하고 업데이트했으므로 Visual Studio 프로젝트를 구성 요소라고 생각할 수 있습니다.Typically, you would consider a Visual Studio project to be a component, because you develop and update those classes at the same time. 프로젝트가 솔루션의 다른 프로젝트에 대해 만드는 호출 또는 프로젝트가 참조하는 다른 어셈블리에 대해 만드는 호출에 스텁 또는 shim을 사용하는 것을 고려할 수 있습니다.You would consider using stubs and shims for calls that the project makes to other projects in your solution, or to other assemblies that the project references.

일반적으로, Visual Studio 솔루션에 포함된 호출에는 스텁을 사용하고 그 밖의 참조된 어셈블리 호출에는 shim을 사용합니다.As a general guide, use stubs for calls within your Visual Studio solution, and shims for calls to other referenced assemblies. 고유 솔루션 내에서는 스텁에 필요한 방식으로 인터페이스를 정의하여 구성 요소를 분리하는 것이 좋기 때문입니다.This is because within your own solution it is good practice to decouple the components by defining interfaces in the way that stubbing requires. 그러나 System.dll 등의 외부 어셈블리에는 별도의 인터페이스 정의가 제공되지 않는 것이 일반적이므로 대신 shim을 사용해야 합니다.But external assemblies such as System.dll typically are not provided with separate interface definitions, so you must use shims instead.

기타 고려 사항:Other considerations are:

성능.Performance. shim은 런타임에 코드를 다시 작성하기 때문에 느리게 실행됩니다.Shims run slower because they rewrite your code at run time. 스텁은 이러한 성능 오버헤드가 없고 가상 메서드처럼 빠릅니다.Stubs do not have this performance overhead and are as fast as virtual methods can go.

sealed 형식의 정적 메서드.Static methods, sealed types. 인터페이스를 구현할 때는 스텁만 사용할 수 있습니다.You can only use stubs to implement interfaces. 따라서 스텁 형식은 정적 메서드, 비가상 메서드, 봉인된 가상 메서드, 봉인된 형식의 메서드 등에 사용할 수 없습니다.Therefore, stub types cannot be used for static methods, non-virtual methods, sealed virtual methods, methods in sealed types, and so on.

내부 형식.Internal types. 스텁과 shim 둘 다 어셈블리 특성 InternalsVisibleToAttribute를 사용하여 액세스할 수 있는 내부 형식에 사용할 수 있습니다.Both stubs and shims can be used with internal types that are made accessible by using the assembly attribute InternalsVisibleToAttribute.

전용 메서드.Private methods. 메서드 시그니처의 모든 형식이 표시되는 경우 shim은 개인 메서드에 대한 호출을 대체할 수 있습니다.Shims can replace calls to private methods if all the types on the method signature are visible. 스텁은 표시되는 메서드만 바꿀 수 있습니다.Stubs can only replace visible methods.

인터페이스 및 추상 메서드.Interfaces and abstract methods. 스텁은 테스트에서 사용할 수 있는 추상 메서드의 구현 및 인터페이스를 제공합니다.Stubs provide implementations of interfaces and abstract methods that can be used in testing. shim에는 메서드 본문이 없기 때문에 인터페이스 및 추상 메서드를 계측할 수 없습니다.Shims can't instrument interfaces and abstract methods, because they don't have method bodies.

일반적으로 코드베이스 안의 종속성에서 격리하려면 스텁 형식을 사용하는 것이 좋습니다.In general, we recommend that you use stub types to isolate from dependencies within your codebase. 인터페이스 뒤에 구성 요소를 숨기면 됩니다.You can do this by hiding the components behind interfaces. shim 형식을 사용하여 테스트 가능한 API를 제공하지 않는 타사 구성 요소에서 격리할 수 있습니다.Shim types can be used to isolate from third-party components that do not provide a testable API.

스텁 시작Getting started with stubs

자세한 내용은 스텁을 사용하여 유닛 테스트를 위한 응용 프로그램의 여러 부분을 서로 격리를 참조하세요.For a more detailed description, see Using stubs to isolate parts of your application from each other for unit testing.

  1. 인터페이스 삽입Inject interfaces

    스텁을 사용하려면 응용 프로그램의 다른 구성 요소에서 클래스를 명시적으로 지정하지 않는 방식으로 테스트할 코드를 작성해야 합니다.To use stubs, you have to write the code you want to test in such a way that it does not explicitly mention classes in another component of your application. "구성 요소"란 함께 개발되어 업데이트되며 일반적으로 하나의 Visual Studio 프로젝트에 포함되는 클래스를 의미합니다.By "component" we mean a class or classes that are developed and updated together, and typically contained in one Visual Studio project. 변수 및 매개 변수는 인터페이스를 사용하여 선언해야 하며 다른 구성 요소의 인스턴스는 팩터리를 사용하여 전달하거나 만들어야 합니다.Variables and parameters should be declared by using interfaces and instances of other components should be passed in or created by using a factory. 예를 들어, StockFeed가 응용 프로그램의 다른 구성 요소에 있는 클래스인 경우 잘못된 것으로 간주됩니다.For example, if StockFeed is a class in another component of the application, then this would be considered bad:

    return (new StockFeed()).GetSharePrice("COOO"); // Bad

    대신, 다른 구성 요소가 실행하고 테스트 용도로 스텁이 실행할 수 있는 인터페이스를 정의합니다.Instead, define an interface that can be implemented by the other component, and which can also be implemented by a stub for test purposes:

    public int GetContosoPrice(IStockFeed feed)  
    { return feed.GetSharePrice("COOO"); }  
    
    Public Function GetContosoPrice(feed As IStockFeed) As Integer  
     Return feed.GetSharePrice("COOO")  
    End Function  
    
  2. Fakes 어셈블리 추가Add Fakes Assembly

    1. 솔루션 탐색기에서 테스트 프로젝트의 참조 목록을 확장합니다.In Solution Explorer, expand the test project's reference list. Visual Basic에서 작업하는 경우 참조 목록을 보기 위해 모든 파일 표시를 선택해야 합니다.If you are working in Visual Basic, you must choose Show All Files in order to see the reference list.

    2. 인터페이스(예: IStockFeed)를 정의한 어셈블리에 대한 참조를 선택합니다.Select the reference to the assembly in which the interface (for example IStockFeed) is defined. 이 참조의 바로 가기 메뉴에서 Fakes 어셈블리 추가를 선택합니다.On the shortcut menu of this reference, choose Add Fakes Assembly.

    3. 솔루션을 다시 빌드합니다.Rebuild the solution.

  3. 테스트에서 스텁 인스턴스를 생성하고 해당 메서드에 대한 코드를 제공합니다.In your tests, construct instances of the stub and provide code for its methods:

    [TestClass]  
    class TestStockAnalyzer  
    {  
        [TestMethod]  
        public void TestContosoStockPrice()  
        {  
          // Arrange:  
    
            // Create the fake stockFeed:  
            IStockFeed stockFeed =   
                 new StockAnalysis.Fakes.StubIStockFeed() // Generated by Fakes.  
                     {  
                         // Define each method:  
                         // Name is original name + parameter types:  
                         GetSharePriceString = (company) => { return 1234; }  
                     };  
    
            // In the completed application, stockFeed would be a real one:  
            var componentUnderTest = new StockAnalyzer(stockFeed);  
    
          // Act:  
            int actualValue = componentUnderTest.GetContosoPrice();  
    
          // Assert:  
            Assert.AreEqual(1234, actualValue);  
        }  
        ...  
    }  
    
    <TestClass()> _  
    Class TestStockAnalyzer  
    
        <TestMethod()> _  
        Public Sub TestContosoStockPrice()  
            ' Arrange:  
            ' Create the fake stockFeed:  
            Dim stockFeed As New StockAnalysis.Fakes.StubIStockFeed  
            With stockFeed  
                .GetSharePriceString = Function(company)  
                                           Return 1234  
                                       End Function  
            End With  
            ' In the completed application, stockFeed would be a real one:  
            Dim componentUnderTest As New StockAnalyzer(stockFeed)  
            ' Act:  
            Dim actualValue As Integer = componentUnderTest.GetContosoPrice  
            ' Assert:  
            Assert.AreEqual(1234, actualValue)  
        End Sub  
    End Class  
    

    여기에서 특별한 부분은 StubIStockFeed 클래스입니다.The special piece of magic here is the class StubIStockFeed. Microsoft Fakes는 참조된 어셈블리의 모든 인터페이스에 대해 스텁 클래스를 생성합니다.For every interface in the referenced assembly, the Microsoft Fakes mechanism generates a stub class. 스텁 클래스의 이름은 인터페이스의 이름에서 파생되며 "Fakes.Stub"가 접두사가 되고 매개 변수 형식 이름이 추가됩니다.The name of the stub class is the derived from the name of the interface, with "Fakes.Stub" as a prefix, and the parameter type names appended.

    스텁은 속성, 이벤트 및 제네릭 메서드의 getter와 setter에 대해서도 생성됩니다.Stubs are also generated for the getters and setters of properties, for events, and for generic methods. 자세한 내용은 스텁을 사용하여 유닛 테스트를 위한 응용 프로그램의 여러 부분을 서로 격리를 참조하세요.For more information, see Using stubs to isolate parts of your application from each other for unit testing.

shim 시작Getting started with shims

(자세한 내용은 shim을 사용하여 유닛 테스트를 위한 다른 어셈블리에서 응용 프로그램 격리를 참조하세요.)(For a more detailed description, see Using shims to isolate your application from other assemblies for unit testing.)

구성 요소에 DateTime.Now에 대한 호출이 포함된 경우를 가정합니다.Suppose your component contains calls to DateTime.Now:

// Code under test:  
    public int GetTheCurrentYear()  
    {  
       return DateTime.Now.Year;  
    }  

실제 버전은 호출할 때마다 매번 다른 값을 반환하므로 테스트하는 동안에는 Now 속성을 shim하려고 합니다.During testing, you would like to shim the Now property, because the real version inconveniently returns a different value at every call.

shim을 사용하려면 응용 프로그램 코드를 수정하거나 특정 방식으로 쓰지 않아도 됩니다.To use shims, you don't have to modify the application code or write it a particular way.

  1. Fakes 어셈블리 추가Add Fakes Assembly

    솔루션 탐색기에서 단위 테스트 프로젝트의 참조를 열고 모조하려는 메서드가 포함된 어셈블리에 대한 참조를 선택합니다.In Solution Explorer, open your unit test project's references and select the reference to the assembly that contains the method you want to fake. 이 예제에서 DateTime 클래스는 System.dll에 있습니다.In this example, the DateTime class is in System.dll. Visual Basic 프로젝트에서 참조를 보려면 모든 파일 표시를 클릭합니다.To see the references in a Visual Basic project, choose Show All Files.

    Fakes 어셈블리 추가를 선택합니다.Choose Add Fakes Assembly.

  2. ShimsContext에 shim 삽입Insert a shim in a ShimsContext

    [TestClass]  
    public class TestClass1  
    {   
            [TestMethod]  
            public void TestCurrentYear()  
            {  
                int fixedYear = 2000;  
    
                // Shims can be used only in a ShimsContext:  
                using (ShimsContext.Create())  
                {  
                  // Arrange:  
                    // Shim DateTime.Now to return a fixed date:  
                    System.Fakes.ShimDateTime.NowGet =   
                    () =>  
                    { return new DateTime(fixedYear, 1, 1); };  
    
                    // Instantiate the component under test:  
                    var componentUnderTest = new MyComponent();  
    
                  // Act:  
                    int year = componentUnderTest.GetTheCurrentYear();  
    
                  // Assert:   
                    // This will always be true if the component is working:  
                    Assert.AreEqual(fixedYear, year);  
                }  
            }  
    }  
    
    <TestClass()> _  
    Public Class TestClass1  
        <TestMethod()> _  
        Public Sub TestCurrentYear()  
            Using s = Microsoft.QualityTools.Testing.Fakes.ShimsContext.Create()  
                Dim fixedYear As Integer = 2000  
                ' Arrange:  
                ' Detour DateTime.Now to return a fixed date:  
                System.Fakes.ShimDateTime.NowGet = _  
                    Function() As DateTime  
                        Return New DateTime(fixedYear, 1, 1)  
                    End Function  
    
                ' Instantiate the component under test:  
                Dim componentUnderTest = New MyComponent()  
                ' Act:  
                Dim year As Integer = componentUnderTest.GetTheCurrentYear  
                ' Assert:   
                ' This will always be true if the component is working:  
                Assert.AreEqual(fixedYear, year)  
            End Using  
        End Sub  
    End Class  
    

    shim 클래스 이름은 원래 형식 이름에 Fakes.Shim 접두사를 추가하여 구성합니다.Shim class names are made up by prefixing Fakes.Shim to the original type name. 매개 변수 이름이 메서드 이름에 추가됩니다.Parameter names are appended to the method name. (System.Fakes에는 어셈블리 참조를 추가할 필요가 없습니다.)(You don't have to add any assembly reference to System.Fakes.)

    이전 예제에서는 정적 메서드에 대해 shim을 사용합니다.The previous example uses a shim for a static method. 인스턴스 메서드에 shim을 사용하려면 형식 이름과 메서드 이름 사이에 AllInstances를 씁니다.To use a shim for an instance method, write AllInstances between the type name and the method name:

System.IO.Fakes.ShimFile.AllInstances.ReadToEnd = ...  

(참조할 ‘System.IO.Fakes’ 어셈블리가 없습니다.(There is no 'System.IO.Fakes' assembly to reference. 네임스페이스는 shim 만들기 프로세스에서 생성됩니다.The namespace is generated by the shim creation process. 그러나 일반적인 방법으로 ‘using’ 또는 ‘Import’를 사용할 수 있습니다.)But you can use 'using' or 'Import' in the usual way.)

또한 특정 인스턴스, 생성자 및 속성에 대한 shim을 만들 수 있습니다.You can also create shims for specific instances, for constructors, and for properties. 자세한 내용은 shim을 사용하여 유닛 테스트를 위한 다른 어셈블리에서 응용 프로그램 격리를 참조하세요.For more information, see Using shims to isolate your application from other assemblies for unit testing.

단원 내용In this section

스텁을 사용하여 단위 테스트를 위한 응용 프로그램의 여러 부분을 서로 격리Using stubs to isolate parts of your application from each other for unit testing

shim을 사용하여 단위 테스트를 위한 다른 어셈블리에서 응용 프로그램 격리Using shims to isolate your application from other assemblies for unit testing

Microsoft Fakes의 코드 생성, 컴파일 및 명명 규칙Code generation, compilation, and naming conventions in Microsoft Fakes