기존 인터페이스가 있습니다 …
public interface ISomeInterface
{
void SomeMethod();
}
그리고 mixin을 사용 하여이 intreface를 확장했습니다 …
public static class SomeInterfaceExtensions
{
public static void AnotherMethod(this ISomeInterface someInterface)
{
// Implementation here
}
}
테스트하고 싶은 클래스가 있습니다 …
public class Caller
{
private readonly ISomeInterface someInterface;
public Caller(ISomeInterface someInterface)
{
this.someInterface = someInterface;
}
public void Main()
{
someInterface.AnotherMethod();
}
}
인터페이스를 조롱하고 확장 메소드에 대한 호출을 확인하려는 테스트 …
[Test]
public void Main_BasicCall_CallsAnotherMethod()
{
// Arrange
var someInterfaceMock = new Mock<ISomeInterface>();
someInterfaceMock.Setup(x => x.AnotherMethod()).Verifiable();
var caller = new Caller(someInterfaceMock.Object);
// Act
caller.Main();
// Assert
someInterfaceMock.Verify();
}
그러나이 테스트를 실행하면 예외가 발생합니다 …
System.ArgumentException: Invalid setup on a non-member method:
x => x.AnotherMethod()
내 질문은, 믹스 인 호출을 조롱하는 좋은 방법이 있습니까?
답변
조롱 프레임 워크로 정적 메소드 (따라서 확장 메소드)를 “직접”조롱 할 수 없습니다. 다른 접근 방식을 구현하는 Microsoft의 무료 도구 인 Moles ( http://research.microsoft.com/en-us/projects/pex/downloads.aspx )를 사용해 볼 수 있습니다 . 다음은 도구에 대한 설명입니다.
Moles는 델리게이트를 기반으로하는 .NET의 테스트 스텁 및 우회 용 경량 프레임 워크입니다.
봉인 된 유형의 비가 상 / 정적 방법을 포함하여 .NET 방법을 우회하는 데 두더지를 사용할 수 있습니다.
테스트 프레임 워크와 함께 Moles를 사용할 수 있습니다 (독립적 임).
답변
이 문제를 해결하기 위해 래퍼를 사용했습니다. 랩퍼 오브젝트를 작성하고 조롱 된 메소드를 전달하십시오.
Paul Irwin의 단위 테스트 를 위한 정적 메소드 조롱을 참조하십시오 . 좋은 예가 있습니다.
답변
입력을 조롱하려고하는 확장 방법의 내부를 발견하고 확장 내부에서 진행중인 것을 조롱해야한다는 것을 알았습니다.
확장 프로그램을 사용하여 메소드에 직접 코드를 추가하는 것으로 보았습니다. 이것은 확장 자체가 아닌 확장 내부에서 일어나는 일을 조롱해야 함을 의미했습니다.
답변
실제 인터페이스를 상속하고 확장 메소드와 동일한 서명을 가진 멤버가있는 테스트 인터페이스를 모의 할 수 있습니다.
그런 다음 테스트 인터페이스를 모의하고 실제 인터페이스를 모의에 추가하고 설정에서 테스트 메소드를 호출 할 수 있습니다.
모의 구현은 원하는 메소드를 호출하거나 메소드가 호출되었는지 간단히 확인할 수 있습니다.
IReal //on which some extension method is defined
{
... SomeRegularMethod(...);
}
static ExtensionsForIReal
{
static ... SomeExtensionMethod(this IReal iReal,...);
}
ITest: IReal
{
//This is a regular method with same name and signature as the extension without the "this IReal iReal" parameter
... SomeExtensionMethod(...);
}
var someMock = new Mock<ITest>();
Mock.As<IReal>(); //ad IReal to the mock
someMock.Setup(x => x.SomeExtensionMethod(...)).Verifiable(); //Calls SomeExtensionMethod on ITest
someMock.As<IReal>().Setup(x => x.SomeRegularMethod(...)).Verifiable(); //Calls SomeRegularMethod on IReal
이 게시물의 Håvard S 솔루션 덕분에 두 개의 인터페이스를 지원하는 모의 객체 를 구현하는 방법 이 있습니다. 일단 그것을 발견하면 테스트 인터페이스와 정적 방법으로 조정하면 케이크 산책이었습니다.
답변
JustMock으로 확장 방법을 쉽게 조롱 할 수 있습니다 . API는 일반 방법을 조롱하는 것과 같습니다. 다음을 고려하세요
public static string Echo(this Foo foo, string strValue)
{
return strValue;
}
이 방법을 정렬하고 확인하려면 다음을 사용하십시오.
string expected = "World";
var foo = new Foo();
Mock.Arrange(() => foo.Echo(Arg.IsAny<string>())).Returns(expected);
string result = foo.Echo("Hello");
Assert.AreEqual(expected, result);
다음은 또한 문서에 대한 링크입니다. Extension Methods Mocking
답변
객체 자체를 래핑 할 때 래퍼 (어댑터 패턴)를 사용하고 싶습니다. 객체의 일부가 아닌 확장 메서드를 래핑하는 데 사용할 것인지 잘 모르겠습니다.
Action, Func, Predicate 또는 delegate 유형의 내부 Lazy Injectable Property을 사용하고 단위 테스트 중에 메소드를 주입 (스왑 아웃) 할 수 있습니다.
internal Func<IMyObject, string, object> DoWorkMethod
{
[ExcludeFromCodeCoverage]
get { return _DoWorkMethod ?? (_DoWorkMethod = (obj, val) => { return obj.DoWork(val); }); }
set { _DoWorkMethod = value; }
} private Func<IMyObject, string, object> _DoWorkMethod;
그런 다음 실제 방법 대신 Func을 호출합니다.
public object SomeFunction()
{
var val = "doesn't matter for this example";
return DoWorkMethod.Invoke(MyObjectProperty, val);
}
더 완전한 예를 보려면 http://www.rhyous.com/2016/08/11/unit-testing-calls-to-complex-extension-methods/를 확인 하십시오.
답변
따라서 Moq를 사용하고 있으며 확장 메소드의 결과를 조롱하려는 경우 사용할 수 있습니다 SetupReturnsDefault<ReturnTypeOfExtensionMethod>(new ConcreteInstanceToReturn())
가있는 Mock 클래스의 인스턴스에서 .
완벽하지는 않지만 단위 테스트 목적으로 잘 작동합니다.