shim을 사용하여 단위 테스트를 위한 다른 어셈블리에서 응용 프로그램 격리
Shim 형식 Fakes Microsoft 프레임 워크를 사용 하 여 수 있도록 두 가지 기술 중 하나를 테스트 환경에서 쉽게 격리 구성 요소는.Shim 코드를 작성 하 여 테스트의 일부로 특정 메서드 호출을 전환 합니다.많은 메서드가 외부 조건에 따라 다른 결과 반환 하지만 shim의 테스트를 제어 하 고 호출할 때마다 일관 된 결과 반환할 수 있습니다.이 테스트를 훨씬 쉽게 작성할 수 있습니다.
Shim을 사용 하 여 솔루션의 일부가 아닌 어셈블리에서 코드를 격리 합니다.솔루션에서 각각의 구성 요소를 격리 시키려면 스텁을 사용 하는 것이 좋습니다.
개요 및 빠른 시작 설명서를 참조 하십시오.Microsoft Fakes를 사용하여 테스트 중인 코드 격리
요구 사항
- Visual Studio Ultimate
볼 (1 h 16) 비디오: 테스트 Un-testable 코드로 Visual Studio 2012에서 Fake
항목 내용
다음은이 항목에서 배웁니다.
Fake 어셈블리를 추가 합니다.
Shimscontext를 사용 합니다.
테스트 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를 호출, 웹 서비스와 통신 하는 프로그램 이므로 단위 테스트에 하드 그들의 논리는 환경에 따라 달라 집니다.
이 심은 종류를 사용할입니다.심 (shim) 형식은 모든.NET 메서드는 사용자 정의 대리자 detour 메커니즘을 제공 합니다.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을 사용 하는 방법
Fake 어셈블리를 추가 합니다.
단위 테스트 프로젝트의 솔루션 탐색기에서 확장 참조.
- Visual Basic 작업 하는 경우를 선택 해야 모든 파일 표시 참조 목록을 보려면 솔루션 탐색기 도구 모음에서.
Shim을 만들려는 클래스 정의가 포함 된 어셈블리를 선택 합니다.DateTime shim 하려는 경우 예를 들어, System.dll을 선택 합니다.
바로 가기 메뉴에서 선택 Fakes 어셈블리 추가.
Shimscontext를 사용 합니다.
심은 형식 단위 테스트 프레임 워크에서 사용 하는 경우 테스트 코드에 래핑해야는 ShimsContext 에 shim의 수명을 제어 합니다.이 필요 하지 않은 경우 Appdomain을 종료 될 때까지 shim에 넘겨진다.쉽게 만들 수 있는 ShimsContext 정적 사용 하는 것 Create() 메서드는 다음 코드와 같이:
//unit test code
[Test]
public void Y2kCheckerTest() {
using(ShimsContext.Create()) {
...
} // clear all shims
}
제대로 각 심은 컨텍스트를 삭제 하는 것이 중요 합니다.최우선으로, 항상 호출의 ShimsContext.Create 내부에 using 문을 적절 한 등록 된 shim 선택을 취소할 수 있도록 합니다.예를 들어, 대체 테스트 메서드에 대 한 shim을 등록할 수는 DateTime.Now 메서드에서 항상 반환 하는 대리자를 사용 하는 처음의 1 월 2000.사용자 테스트 메서드에서 등록 된 shim을 지우려면 잊은 경우, 테스트 실행의 나머지 부분을 항상 반환 합니다 Datetime.now는의 1 월 2000의 첫 번째 값입니다.이 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 원본 형식 이름입니다.
작업 shim을 삽입 하 여 자유롭게 는 테스트 대상 응용 프로그램의 코드입니다.원래 메서드 호출 발생 위치에 관계 없이 실제 메서드를 호출 하는 대신 shim 코드를 호출할 수 있도록 Fake 시스템은 detour를 수행 합니다.
자유롭게 작성 되어 실행된 시 삭제 됩니다.항상 한 detour의 수명 내에서 만들어야는 ShimsContext.삭제 될 때 활성 상태 였던 동안 만든 모든 shim이 제거 됩니다.이 작업을 수행 하는 가장 좋은 방법은 내부에 있는 using 문.
Fake 네임 스페이스는 존재 하지 않는 없다는 빌드 오류를 볼 수 있습니다.다른 컴파일 오류가 있을 경우이 오류가 나타나는 경우가 있습니다.다른 오류를 수정 하 고이 사라질 것입니다.
다양 한 종류의 방법에 대 한 shim
심은 형식을 사용자가 직접 대리자를 가상이 아닌 메서드 또는 정적 메서드를 포함 하 여 모든.NET 메서드를 대체할 수 있습니다.
정적 메서드
Shim 정적 메서드에 연결할 속성 심은 형식으로 배치 됩니다.각 속성은 대리자의 대상 메서드를 연결 하는 데 사용할 수 있는 setter만 있습니다.예를 들어, 클래스를 제공 MyClass 정적 메서드 MyMethod.
//code under test
public static class MyClass {
public static int MyMethod() {
...
}
}
우리가 심은에 첨부할 수 있습니다 MyMethod 는 항상 5를 반환 합니다.
// unit test code
ShimMyClass.MyMethod = () =>5;
(모든 인스턴스)에 대 한 인스턴스 메서드
마찬가지로 정적 메서드, 인스턴스 메서드 모든 인스턴스에 대해 shimmed 수 있습니다.이러한 shim 연결할 속성 혼동을 피하기 위해 AllInstances 라는 중첩된 형식에 배치 됩니다.예를 들어, 클래스를 제공 MyClass 인스턴스 메서드 MyMethod.
// code under test
public class MyClass {
public int MyMethod() {
...
}
}
Shim을 첨부할 수 있습니다 MyMethod 인스턴스 없이 5 항상 반환 합니다.
// 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을 설정할 속성 심은 형식의 인스턴스 메서드입니다.인스턴스화된 심은 종류별로 원시 shimmed 형식의 인스턴스와 연결 이기도합니다.
예를 들어, 클래스를 제공 MyClass 인스턴스 메서드 MyMethod.
// code under test
public class MyClass {
public int MyMethod() {
...
}
}
첫 번째는 항상 5를 반환 하 고 10 초를 항상 반환 하도록 우리가 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;
심 (shim) 형식 이므로 일반적으로 간단 하 게 사용할 수 있도록 심은 형식 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) 구성원 속성을 기본 기본 형식에 대 한 shim을 만들고 자식 인스턴스 shim 기본 클래스의 생성자에 매개 변수로 전달 하 여 액세스할 수 있습니다.
예를 들어, 클래스를 제공 MyBase 인스턴스 메서드 MyMethod 및 하위 MyChild.
public abstract class MyBase {
public int MyMethod() {
...
}
}
public class MyChild : MyBase {
}
여기서의 shim을 설정할 수 있습니다 MyBase 를 만들어 새 ShimMyBase shim:
// unit test code
var child = new ShimMyChild();
new ShimMyBase(child) { MyMethod = () => 5 };
참고 자식 형식을 shim 기본 심은 생성자에 매개 변수로 전달 하면 자식 인스턴스를 암시적으로 변환 됩니다.
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 { ... } }
}
정적 생성자
심 (shim) 형식을 노출 하는 정적 메서드 StaticConstructor shim 형식의 정적 생성자를.정적 생성자 실행 됩니다만, 확인 해야 하므로 모든 형식의 멤버에 액세스 하기 전에 shim 구성 됩니다.
종료자
종료자는 Fake에서 지원 되지 않습니다.
전용 메서드
심은 속성이 서명에서 볼 수 있는 형식 하기만 하는 전용 메서드에 대 한 Fake 코드 생성기를 만듭니다 I.e. 매개 변수 형식 및 반환 형식이 표시 합니다.
바인딩 인터페이스
Shimmed 형식이 인터페이스를 구현 하는 경우 해당 인터페이스의 모든 멤버를 한 번에 바인딩할 수 있도록 하는 메서드는 코드 생성기를 방출 합니다.
예를 들어, 클래스를 제공 MyClass 구현 IEnumerable<int>.
public class MyClass : IEnumerable<int> {
public IEnumerator<int> GetEnumerator() {
...
}
...
}
여기서의 구현은 shim 수 IEnumerable<int> Bind 메서드를 호출 하 여 Myclass에서:
// unit test code
var shimMyClass = new ShimMyClass();
shimMyClass.Bind(new List<int> { 1, 2, 3 });
Shimmyclass의 생성 된 형식 구조는 다음 코드와 유사합니다.
// Fakes generated code
public class ShimMyClass : ShimBase<MyClass> {
public ShimMyClass Bind(IEnumerable<int> target) {
...
}
}
기본 동작을 변경합니다.
각 생성 된 shim 형식 인스턴스를 보유 하 고 있는 IShimBehavior 인터페이스를 통해의 ShimBase<T>.InstanceBehavior 속성.클라이언트가 명시적으로 shimmed 되지 않은 인스턴스 멤버를 호출할 때마다 동작이 사용 됩니다.
동작을 명시적으로 설정 되지 않은 경우는 정적 반환 되는 인스턴스를 사용 합니다 ShimsBehaviors.Current 속성입니다.기본적으로이 속성은 throw 된 동작 반환 된 NotImplementedException 예외입니다.
설정 하 여이 문제를 언제 든 지 변경할 수 있습니다의 InstanceBehavior shim 인스턴스 속성입니다.예를 들어, 다음 코드 조각 shim을 아무 작업도 하지 않습니다 또는 반환 형식의 기본값을 반환 하는 동작을 변경, 즉, default (t):
// unit test code
var shim = new ShimMyClass();
//return default(T) or do nothing
shim.InstanceBehavior = ShimsBehaviors.DefaultValue;
동작 전역 shimmed 모든 인스턴스에 대해를 변경할 수 있습니다의 InstanceBehavior 속성이 정적으로 설정 하 여 명시적으로 설정 되지 않은 ShimsBehaviors.Current 속성:
// unit test code
// change default shim for all shim instances
// where the behavior has not been set
ShimsBehaviors.Current =
ShimsBehaviors.DefaultValue;
검색 환경에 액세스
할당 하 여 특정 형식의 정적 메서드를 포함 하 여 모든 멤버에는 비헤이비어를 연결 하는 것이 가능은 ShimsBehaviors.NotImplemented 정적 속성 동작 Behavior 심은 해당 형식의:
// unit test code
// assigning the not implemented behavior
ShimMyClass.Behavior = ShimsBehaviors.NotImplemented;
// shorthand
ShimMyClass.BehaveAsNotImplemented();
동시성
심 (shim) 형식 Appdomain의 모든 스레드에 적용 및 스레드 선호도 없습니다.동시성을 지원 하 여 test runner를 사용 하는 경우이 중요 한 사실입니다: shim 형식과 관련 된 테스트를 동시에 실행할 수 없습니다.이 속성은 런타임에서 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 기본 클래스 라이브러리의 모든 형식에서 사용할 수 없습니다 mscorlib 및 시스템.
외부 리소스
지침
Visual Studio 2012 2 장 연속 배달 테스트: 단위 테스트: 내부 테스트
참고 항목
개념
Microsoft Fakes를 사용하여 테스트 중인 코드 격리