다음을 통해 공유


shim을 사용하여 단위 테스트를 위한 다른 어셈블리에서 응용 프로그램 격리

심은 형식 은 쉽게 격리 된 테스트 환경에서 구성 요소는 Microsoft Fakes 프레임 워크를 사용하는 두 가지 기술 중 하나입니다.Shim은 전환 테스트의 일부로 작성 하는 코드에 특정 메서드를 호출 합니다.많은 메서드가 외부 조건에 따라 다른 결과가 반환되지만 심은 테스트를 제어하고 모든 호출에 대해 일관된 결과를 반환할 수 있습니다.따라서 테스트는 훨씬 더 쉽게 작성할 수 있습니다.

솔루션에 포함되지 않은 어셈블리에서 코드를 격리하려면 shim을 사용 합니다.솔루션에서 각각의 구성 요소를 분리 스텁을 사용하는 것이 좋습니다.

개요 및 빠른 시작에 대한 설명서 Microsoft Fakes를 사용하여 테스트 중인 코드 격리를 참조 하십시오.

요구 사항

  • Visual Studio Ultimate

(1 h 16) 비디오: Fake 2012 Visual Studio를 사용 하 여 Un-testable 코드 테스트를 참조하십시오.

항목 내용

이 항목에서 설명은 다음과 같습니다.

예: Y2K 버그

shim 사용 방법

  • Fakes 어셈블리 추가

  • ShimsContext 사용

  • shim을 사용하여 테스트 작성

다양한 메서드에 대한 shim

스텁의 기본 동작 변경

검색 환경에 액세스

동시성

심 (shim) 메서드에서 원래 메서드를 호출합니다.

제한

예: Y2K 버그

2000 년 1 월 1 일에 예외를 throw 하는 메서드를 살펴보겠습니다.

// code under test
public static class Y2KChecker {
    public static void Check() {
        if (DateTime.Now == new DateTime(2000, 1, 1))
            throw new ApplicationException("y2kbug!");
    }
}

이 메서드를 테스트는 프로그램에 따라 달라 지므로 특히 문제가 DateTime.Now, 컴퓨터에 의존 하는 방법의 클럭는 환경 종속적 명확 하지 않은 방법입니다.또한 해당 DateTime.Now 정적 속성 이므로 스텁 형식 여기에 사용할 수 없습니다.이 문제는 단위 테스트에서 격리 문제를 유발: 논리는 환경에 따라 달라 지므로 직접 데이터베이스 Api 호출하여 웹 서비스와 통신 하 고에 있는 프로그램은 단위 테스트를 합니다.

이것은 심은 종류를 사용해야 합니다.심은 종류 detour.NET 메서드는 사용자 정의 대리자를 메커니즘을 제공 합니다.심은 유형은 Fake 생성기에서 코드 생성 및 새 메서드 구현을 지정 shim 종류를 호출하는 대리자를 사용합니다.

다음 테스트에서는 심은 형식 사용 ShimDateTime, DateTime.Now의 사용자 지정 구현을 제공해야 합니다.:

//unit test code
// create a ShimsContext cleans up shims 
using (ShimsContext.Create()
    // hook delegate to the shim method to redirect DateTime.Now
    // to return January 1st of 2000
    ShimDateTime.NowGet = () => new DateTime(2000, 1, 1);
    Y2KChecker.Check();
}

shim 사용 방법

Fakes 어셈블리 추가

  1. 솔루션 탐색기에서 테스트 프로젝트의 참조 목록을 확장합니다.

    • Visual Basic 작업 하는 경우 참조목록을 보려면 솔루션 탐색기 도구 모음에서 모든 파일 표시 를 선택해야 합니다.
  2. Shim을 작성 하려면 클래스 정의가 들어 있는 어셈블리를 선택 합니다.예를 들어 shim DateTime 하려는 경우 System.dll 선택합니다.

  3. 바로 가기 메뉴에서 새 다이어그램 추가를 선택합니다.

ShimsContext 사용

심 (shim) 형식을 사용하여 단위 테스트 프레임 워크를 할 때 shim 프로그램의 수명을 제어하기 위해 ShimsContext 에서 테스트 코드를 묶어야 합니다.더 이상이 필요 하지 않으면, AppDomain이 종료 될 때까지 shim에 넘겨진다.ShimsContext 를 만드는 가장 쉬운 방법 정적 Create() 메서드를 사용하여 다음 코드와 같이 하는 것입니다.:

//unit test code
[Test]
public void Y2kCheckerTest() {
  using(ShimsContext.Create()) {
    ...
  } // clear all shims
}

각 심 컨텍스트를 제대로 처리하는 것은 중요합니다.위치 조정 컨트롤과 같이 항상 using 문의 내의 ShimsContext.Create 를 호출하여 적절하게 등록된 shim 삭제를 보장합니다.예를 들어, 대체 하는 테스트 방법에 대해 2000년 1월 1일을 항상 반환하는 대리자와 함께 DateTime.Now 메서드를 대신하는 테스트 메서드에 대해 shim을 등록할 수 있습니다.잊어버렸을 때 테스트 메서드에서 등록 된 shim을 지우려면, 테스트 실행의 나머지는 반환 항상 DateTime.Now는 2000년 1월 1일입니다.Suprising와 혼동할 수 있습니다.

shim을 사용하여 테스트 작성

테스트 코드에서 가짜 메서드에 대해 detour 를 삽입합니다.예를 들면 다음과 같습니다.

[TestClass]
public class TestClass1
{ 
        [TestMethod]
        public void TestCurrentYear()
        {
            int fixedYear = 2000;

            using (ShimsContext.Create())
            {
              // Arrange:
                // Detour 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 접두사를 추가하여 구성합니다.

Shims 작업을 detours 를 아래 테스트 응용의 코드에 삽입하여 작업합니다.원래 메서드 호출 발생 위치에 관계없이 실제 메서드를 호출하는 대신 shim 코드를 호출할 수 있도록 Fake 시스템 detour를 수행 합니다.

자유롭게 만들고 실행 시 삭제를 확인 합니다.ShimsContext 기간 내 detour를 항상 만들어야 합니다.삭제될 때 활성 상태를 만든 모든 shim이 제거 됩니다.가장 좋은 방법은 using 문 내에서 있습니다.

Fake 네임 스페이스가 존재 하지 않는 빌드 오류 메시지가 나타날 수 있습니다.다른 컴파일 오류가 있을 경우 이 오류가 나타나는 경우가 있습니다.다른 오류를 수정하고 사라질 것입니다.

다양한 메서드에 대한 shim

심 (shim) 형식을 사용 사용자가 직접 대리자를 사용하여 가상이 아닌 메서드 또는 정적 메서드를 포함하여 모든.NET 메서드를 대체할 수 있습니다.

정적 메서드

Shim 정적 메서드에 연결할 속성 심은 형식에 배치 됩니다.각 속성에는 대상 메서드에 대리자 연결을 사용할 수 있는 stter이 있습니다.예를 들어, 정적 메서드 MyMethod 와 함께 MyClass 클래스가 주어집니다.

//code under test
public static class MyClass {
    public static int MyMethod() {
        ...
    }
}

Shim을 항상 5를 반환하는 MyMethod 에 연결할 수 있습니다:

// unit test code
ShimMyClass.MyMethod = () =>5;

모든 인스턴스에 대한 인스턴스 메서드

마찬가지로 정적 메서드와 인스턴스 메서드 모두 shimmed일 수 있습니다.속성을 연결된 shim과 혼동을 피하기 위해 AllInstances 라는 중첩된 형식으로 배치 됩니다.예를 들어, 인스턴스 메서드 MyMethod 와 함께 MyClass 클래스가 주어집니다.

// code under test
public class MyClass {
    public int MyMethod() {
        ...
    }
}

인스턴스와 무관하게 항상 5를 반환하는 MyMethod 에 Shim을 첨부할 수 있습니다:

// unit test code
ShimMyClass.AllInstances.MyMethod = () => 5;

ShimMyClass의 생성 된 형식 구조는 다음 코드와 같습니다.

// Fakes generated code
public class ShimMyClass : ShimBase<MyClass> {
    public static class AllInstances {
        public static Func<MyClass, int>MyMethod {
            set {
                ...
            }
        }
    }
}

Fakes 공지를 이 경우 첫 번째 인수는 대리자의 런타임 인스턴스에 전달 합니다.

단일 런타임 인스턴스에 대한 인스턴스 메서드

인스턴스 메서드는 호출 수신자에 따라 다른 대리자에 의해 또한 shimmed 수 있습니다.이렇게 하면 같은 인스턴스 메서드는 각 형식의 인스턴스에 대해 서로 다른 동작을 합니다.이러한 shim을 설정 하려면 속성은 자체 심은 형식의 인스턴스 메서드입니다.각 shim 인스턴스화된 형식이 원시 shimmed 형식의 인스턴스와의 연결이기도 합니다.

예를 들어, 인스턴스 메서드 MyMethod 와 함께 MyClass 클래스가 주어집니다.

// code under test
public class MyClass {
    public int MyMethod() {
        ...
    }
}

항상 두 번째 10을 반환 하며 첫 번째는 항상 5를 반환 MyMethod의 두 심은 종류를 설정할 수 있습니다:

// unit test code
var myClass1 = new ShimMyClass()
{
    MyMethod = () => 5
};
var myClass2 = new ShimMyClass { MyMethod = () => 10 };

ShimMyClass의 생성 된 형식 구조는 다음 코드와 같습니다.

// Fakes generated code
public class ShimMyClass : ShimBase<MyClass> {
    public Func<int> MyMethod {
        set {
            ...
        }
    }
    public MyClass Instance {
        get {
            ...
        }
    }
}

실제 shimmed 형식 인스턴스에 인스턴스 속성을 통해 액세스할 수 있습니다:

// unit test code
var shim = new ShimMyClass();
var instance = shim.Instance;

심은 형식에 shimmed 형식으로 암시적 변환이 심은 종류는 일반적으로 간단하게 사용할 수 있습니다:

// unit test code
var shim = new ShimMyClass();
MyClass instance = shim; // implicit cast retrieves the runtime
                         // instance

생성자

생성자는 개체 앞에 심은 종류를 연결하기 위해 shimmed될 수 있습니다.각 생성자 심은 형식의 정적 메서드와 생성자에 제공 됩니다.예를 들어, MyClass 클래스는 정수는 생성자를 사용하여 주어집니다:

// code under test
public class MyClass {
    public MyClass(int value) {
        this.Value = value;
    }
    ...
}

모든 이후 인스턴스 생성자에서 값에 관계없이 값 getter를 호출-5를 반환하여 심은 형식의 생성자를 설정합니다.

// unit test code
ShimMyClass.ConstructorInt32 = (@this, value) => {
    var shim = new ShimMyClass(@this) {
        ValueGet = () => -5
    };
};

참고 심은 종류별로 두 생성자를 노출 합니다.기본 생성자는 생성자 인수 생성자 shim만 사용하여 shimmed 인스턴스가 수행되는 동안 새로운 인스턴스가 필요할 때 사용되어야 합니다.

// unit test code
public ShimMyClass() { }
public ShimMyClass(MyClass instance) : base(instance) { }

생성된 형식 구조의 ShimMyClass followoing 코드와 유사합니다.

// Fakes generated code
public class ShimMyClass : ShimBase<MyClass>
{
    public static Action<MyClass, int> ConstructorInt32 {
        set {
            ...
        }
    }

    public ShimMyClass() { }
    public ShimMyClass(MyClass instance) : base(instance) { }
    ...
}

기본 멤버

기본 형식에 대한 shim을 만들고 자식 인스턴스를 심은 기본 클래스의 생성자에 매개 변수로 전달하여 심은 기본 구성원 속성을 액세스할 수 있습니다.

예를 들어, MyBase 클래스가 인스턴스 메서드 MyMethod 및 하위 MyChild와 함께 주어집니다:

public abstract class MyBase {
    public int MyMethod() {
        ...
    }
}

public class MyChild : MyBase {
}

새 ShimMyBase shim을 생성하여 MyBase 의 shim을 설정합니다.

// unit test code
var child = new ShimMyChild();
new ShimMyBase(child) { MyMethod = () => 5 };

자식 심은 종류 심은 기본 생성자에 매개 변수로 전달될 때 자식 인스턴스를 암시적으로 변환되는 것을 참고합니다.

ShimMyChild 및 ShimMyBase의 생성된 형식 구조는 다음 코드와 유사합니다.

// Fakes generated code
public class ShimMyChild : ShimBase<MyChild> {
    public ShimMyChild() { }
    public ShimMyChild(Child child)
        : base(child) { }
}
public class ShimMyBase : ShimBase<MyBase> {
    public ShimMyBase(Base target) { }
    public Func<int> MyMethod
    { set { ... } }
}

정적 생성자

심은 형식은 정적 메서드를 StaticConstructor shim 형식의 정적 생성자에 노출시킵니다.일단 정적 생성자가 실행되므로 shim 형식의 모든 멤버에 액세스하기 전에 구성 됩니다.

종료자

종료자는 Fake에서는 지원되지 않습니다.

전용 메서드

Fake 코드 생성기만 볼 수 있는 형식에서 있는 서명, 즉, 전용 메서드를 심은 속성울 만듭니다. 매개 변수 형식 및 반환 형식이 표시됩니다.

바인딩 인터페이스

Shimmed 형식이 인터페이스를 구현하는 코드 생성기 인터페이스에서 모든 구성원을 한 번에 바인딩할 수 있도록 하는 메서드를 내보냅니다.

예를 들어, IEnumerable<int>을 구현하는 MyClass 클래스가 주어집니다.

public class MyClass : IEnumerable<int> {
    public IEnumerator<int> GetEnumerator() {
        ...
    }
    ...
}

바인드 메서드의 호출에 의해 MyClass 내의 IEnumerable<int> 의 구현을 shim할 수 있습니다.

// unit test code
var shimMyClass = new ShimMyClass();
shimMyClass.Bind(new List<int> { 1, 2, 3 });

생성된 형식 구조의 ShimMyClass followoing 코드와 유사합니다.

// Fakes generated code
public class ShimMyClass : ShimBase<MyClass> {
    public ShimMyClass Bind(IEnumerable<int> target) {
        ...
    }
}

스텁의 기본 동작 변경

생성된 shim 종류는 ShimBase<T>.InstanceBehavior 속성을 통해 IShimBehavior 인터페이스의 인스턴스를 보유할 수 있습니다.동작은 클라이언트 shimmed된 인스턴스 멤버를 명시적으로를 호출할 때마다 사용됩니다.

정적에서 반환된 인스턴스를 사용하는 동작이 ShimsBehaviors.Current 속성에 의해 명시적으로 설정되지 안습니다.기본적으로이 속성은 NotImplementedException 예외를 throw 하는 동작이 반환됩니다.

이 동작을 인스턴스에 InstanceBehavior 속성을 설정하여 언제든 지 변경할 수 있습니다.예를 들어, 다음 코드 조각은 아무것도 하지 않거나 반환 형식-즉,default(T)의 기본값을 반환 하는 shim을 바꿉니다.

// unit test code
var shim = new ShimMyClass();
//return default(T) or do nothing
shim.InstanceBehavior = ShimsBehaviors.DefaultValue;

동작은 정적 ShimsBehaviors.Current 속성의 설정에 의해 명시적으로 설정되지 않는 InstanceBehavior 속성에 대한 모든 shimmed 된 인스턴스에 대해 전체적으로 바뀔 수 있습니다.

// unit test code
// change default shim for all shim instances
// where the behavior has not been set
ShimsBehaviors.Current = 
    ShimsBehaviors.DefaultValue;

검색 환경에 액세스

shim 형식에 해당하는 Behavior 정적 속성에 ShimsBehaviors.NotImplemented 를 할당하여 특정 영역의 정적 메서드를 포함하여 모든 멤버들을 연결하는 것이 가능합니다.

// unit test code
// assigning the not implemented behavior
ShimMyClass.Behavior = ShimsBehaviors.NotImplemented;
// shorthand
ShimMyClass.BehaveAsNotImplemented();

동시성

심은 형식을 AppDomain에 있는 모든 스레드를 적용하고 스레드 선호도 없습니다.동시성을 지원하는 테스트 러너를 사용하려는 경우 심은 형식과 관련된 테스트를 동시에 실행할 수 없습니다.이 속성은 런타임에서 Fake enfored 없습니다.

심 (shim) 메서드에서 원래 메서드를 호출합니다.

메서드에 전달된 파일의 이름을 확인한 후 파일 시스템에 실제로 텍스트 작성하고자 한다고 가정합니다.이러한 경우에 심은 메서드 중에 원래 메서드를 호출하려고 합니다.

이 문제를 해결하기 위한 첫 번째 방법은 대리자를 사용하여 원래 메서드를 호출하고 ShimsContext.ExecuteWithoutShims() 는 다음 코드에서와 같습니다:

// unit test code
ShimFile.WriteAllTextStringString = (fileName, content) => {
  ShimsContext.ExecuteWithoutShims(() => {

      Console.WriteLine("enter");
      File.WriteAllText(fileName, content);
      Console.WriteLine("leave");
  });
};

또 다른 방법은 null, 메서드를 호출 하는 원래 shim 복원 shim을 설정할 수 있습니다.

// unit test code
ShimsDelegates.Action<string, string> shim = null;
shim = (fileName, content) => {
  try {
    Console.WriteLine("enter”);
    // remove shim in order to call original method
    ShimFile.WriteAllTextStringString = null;
    File.WriteAllText(fileName, content);
  }
  finally
  {
    // restore shim
    ShimFile.WriteAllTextStringString = shim;
    Console.WriteLine("leave");
  }
};
// initialize the shim
ShimFile.WriteAllTextStringString = shim;

제한

Shim은 .NET 기본 클래스 라이브러리 mscorlibSystem 의 모든 형식에서 사용할 수 없습니다.

외부 리소스

지침

Visual Studio 2012를 사용한 연속 배달 테스트 – 2장: 단위 테스트: 내부 테스트

참고 항목

개념

Microsoft Fakes를 사용하여 테스트 중인 코드 격리

기타 리소스

Peter Provost 블로그: Visual Studio 2012 Shim

(1 h 16) 비디오: Fake 2012 Visual Studio를 사용 하 여 Un-testable 코드 테스트