정적 메서드 모의
최근에는 단위 테스트에 Moq 를 사용하기 시작했습니다 . Moq를 사용하여 테스트 할 필요가없는 클래스를 모의합니다.
일반적으로 정적 메서드를 어떻게 처리합니까?
public void foo(string filePath)
{
File f = StaticClass.GetFile(filePath);
}
이 정적 메서드가 StaticClass.GetFile()
어떻게 조롱 될 수 있습니까?
추신 : Moq 및 단위 테스트에 대해 추천 해 주신 모든 자료에 감사드립니다.
Moq 또는 Rhinomocks와 같은 모의 프레임 워크는 개체의 모의 인스턴스 만 만들 수 있습니다. 즉, 정적 메서드 모의는 불가능합니다.
Google 에서 자세한 정보를 검색 할 수도 있습니다 .
또한 이전에 StackOverflow에 대한 몇 가지 질문이 여기 , 여기 및 여기에 있습니다 .
@ Pure.Krome : 좋은 답변이지만 몇 가지 세부 사항을 추가하겠습니다
@Kevin : 코드에 가져올 수있는 변경 사항에 따라 솔루션을 선택해야합니다.
변경할 수있는 경우 일부 종속성 주입으로 코드를 더 테스트 할 수 있습니다. 할 수 없다면 좋은 격리가 필요합니다.
무료 모의 프레임 워크 (Moq, RhinoMocks, NMock ...)를 사용하면 델리게이트, 인터페이스 및 가상 메서드 만 모의 할 수 있습니다. 따라서 정적, 봉인 및 비가 상 방법의 경우 3 가지 솔루션이 있습니다.
- TypeMock Isolator (모든 것을 모의 할 수 있지만 비싸다)
- Telerik의 JustMock (신규, 저렴하지만 여전히 무료는 아님)
- Moles of Microsoft (단독을위한 유일한 무료 솔루션)
무료이고 효율적이며 Moq와 같은 람다 식을 사용하기 때문에 Moles를 추천 합니다. 한 가지 중요한 세부 사항 : 두더지는 모의가 아닌 스텁을 제공합니다. 따라서 인터페이스 및 델리게이트에 Moq를 계속 사용할 수 있습니다.)
Mock : 인터페이스를 구현하고 특정 메서드에서 throw 할 반환 / 예외 값을 동적으로 설정하는 기능을 허용하고 특정 메서드가 호출되었는지 여부를 확인하는 기능을 제공하는 클래스입니다.
스텁 : 모의 클래스와 비슷 하지만 메서드가 호출되었는지 / 호출되지 않았는지 확인하는 기능을 제공하지 않는다는 점이 다릅니다.
.NET에서는 MOQ 및 기타 모의 라이브러리를 제외한 가능성이 있습니다. 모의하려는 정적 메서드가 포함 된 어셈블리에서 솔루션 탐색기를 마우스 오른쪽 단추로 클릭하고 Add Fakes Assembly를 선택해야합니다 . 다음으로 어셈블리 정적 메서드를 자유롭게 모의 할 수 있습니다.
System.DateTime.Now
정적 메서드 를 모의한다고 가정합니다 . 예를 들어 다음과 같이하십시오.
using (ShimsContext.Create())
{
System.Fakes.ShimDateTime.NowGet = () => new DateTime(1837, 1, 1);
Assert.AreEqual(DateTime.Now.Year, 1837);
}
각 정적 속성 및 메서드에 대해 유사한 속성이 있습니다.
nuget에서 제공 하는 Pose 라이브러리를 사용 하여이를 달성 할 수 있습니다 . 무엇보다도 정적 메서드를 모의 할 수 있습니다. 테스트 방법에서 다음을 작성하십시오.
Shim shim = Shim.Replace(() => StaticClass.GetFile(Is.A<string>()))
.With((string name) => /*Here return your mocked value for test*/);
var sut = new Service();
PoseContext.Isolate(() =>
result = sut.foo("filename") /*Here the foo will take your mocked implementation of GetFile*/, shim);
자세한 내용은 여기를 참조하십시오 https://medium.com/@tonerdo/unit-testing-datetime-now-in-c-without-using-interfaces-978d372478e8
나는 Pose를 좋아했지만 알려진 문제로 보이는 InvalidProgramException 던지기를 멈출 수 없었습니다 . 이제 다음 과 같이 Smocks를 사용 하고 있습니다.
Smock.Run(context =>
{
context.Setup(() => DateTime.Now).Returns(new DateTime(2000, 1, 1));
// Outputs "2000"
Console.WriteLine(DateTime.Now.Year);
});
테스트 목적으로 외부에서 설정할 수있는 대리자를 호출하기 위해 정적 메서드를 리팩토링하는 개념을 가지고 놀았습니다.
이것은 테스트 프레임 워크를 사용하지 않으며 완전히 맞춤화 된 솔루션이지만 리팩터링은 호출자의 서명에 영향을주지 않으므로 상대적으로 안전합니다.
이 작업을 수행하려면 정적 메서드에 대한 액세스 권한이 있어야하므로 System.DateTime
.
다음은 두 개의 매개 변수를 사용하는 반환 유형과 반환 유형이없는 제네릭 하나 인 두 가지 정적 메서드를 만든 곳에서 놀아 온 예제입니다.
주요 정적 클래스 :
public static class LegacyStaticClass
{
// A static constructor sets up all the delegates so production keeps working as usual
static LegacyStaticClass()
{
ResetDelegates();
}
public static void ResetDelegates()
{
// All the logic that used to be in the body of the static method goes into the delegates instead.
ThrowMeDelegate = input => throw input;
SumDelegate = (a, b) => a + b;
}
public static Action<Exception> ThrowMeDelegate;
public static Func<int, int, int> SumDelegate;
public static void ThrowMe<TException>() where TException : Exception, new()
=> ThrowMeDelegate(new TException());
public static int Sum(int a, int b)
=> SumDelegate(a, b);
}
단위 테스트 (xUnit 및 Shouldly)
public class Class1Tests : IDisposable
{
[Fact]
public void ThrowMe_NoMocking_Throws()
{
Should.Throw<Exception>(() => LegacyStaticClass.ThrowMe<Exception>());
}
[Fact]
public void ThrowMe_EmptyMocking_DoesNotThrow()
{
LegacyStaticClass.ThrowMeDelegate = input => { };
LegacyStaticClass.ThrowMe<Exception>();
true.ShouldBeTrue();
}
[Fact]
public void Sum_NoMocking_AddsValues()
{
LegacyStaticClass.Sum(5, 6).ShouldBe(11);
}
[Fact]
public void Sum_MockingReturnValue_ReturnsMockedValue()
{
LegacyStaticClass.SumDelegate = (a, b) => 6;
LegacyStaticClass.Sum(5, 6).ShouldBe(6);
}
public void Dispose()
{
LegacyStaticClass.ResetDelegates();
}
}
나는 이것이 조금 늦었다는 것을 알고 있지만이 원형 교차로 솔루션을 사용하면 Moq를 사용하여 정적 메서드를 모의 할 수 있습니다.
이를 위해 저는 Placeholder
static method라는 하나의 메서드를 가진 클래스를 만들었습니다 StaticClass.GetFile
.
public class Placeholder{
//some empty constructor
public File GetFile(){
File f = StaticClass.GetFile(filePath);
return f;
}
}
그런 다음, 호출하는 대신 StaticClass.GetFile
에 foo
, 나는의 인스턴스를 생성 Placeholder
및 호출 GetFile
기능.
public void foo(string filePath)
{
Placeholder p = new Placeholder();
File f = p.GetFile(filePath);
}
이제 단위 테스트에서 mock을 시도하는 대신 클래스 에서 StaticClass.GetFile
비 정적 GetFile
메서드 를 모의 할 수있었습니다 Placeholder
.
참고 URL : https://stackoverflow.com/questions/5864076/mocking-static-methods
'developer tip' 카테고리의 다른 글
Android 서비스는 항상 실행되어야 함 (일시 중지 또는 중지하지 않음) (0) | 2020.11.15 |
---|---|
iPhone 인앱 구매 스크린 샷 (0) | 2020.11.15 |
boost :: shared_ptr 사용에서 std :: shared_ptr로 전환해야합니까? (0) | 2020.11.15 |
동일한 "id"를 가진 여러 요소가있을 때 jQuery는 어떻게 작동합니까? (0) | 2020.11.15 |
루프 내에서 함수를 만들지 마십시오. (0) | 2020.11.15 |