[C#] Moq : 모의 서비스의 메소드에 전달 된 매개 변수를 얻는 방법

이 수업을 상상해보십시오

public class Foo {

    private Handler _h;

    public Foo(Handler h)
    {
        _h = h;
    }

    public void Bar(int i)
    {
        _h.AsyncHandle(CalcOn(i));
    }

    private SomeResponse CalcOn(int i)
    {
        ...;
    }
}

Foo 테스트에서 Mo (q) cking Handler, Bar()전달 된 내용을 _h.AsyncHandle어떻게 확인할 수 있습니까?



답변

Mock.Callback-method를 사용할 수 있습니다 :

var mock = new Mock<Handler>();
SomeResponse result = null;
mock.Setup(h => h.AnsyncHandle(It.IsAny<SomeResponse>()))
    .Callback<SomeResponse>(r => result = r);

// do your test
new Foo(mock.Object).Bar(22);
Assert.NotNull(result);

전달 된 인수에서 간단한 것을 확인하려면 직접 할 수도 있습니다.

mock.Setup(h => h.AnsyncHandle(It.Is<SomeResponse>(response => response != null)));


답변

Gamlor의 대답은 저에게 효과적이지만 John Carpenter의 의견을 확장 할 것이라고 생각했습니다. 하나 이상의 매개 변수와 관련된 솔루션을 찾고 있었기 때문입니다. 이 페이지를 우연히 본 다른 사람들도 비슷한 상황에 처해있을 것이라고 생각했습니다. Moq documentation 에서이 정보를 찾았습니다 .

Gamlor의 예제를 사용하지만 AsyncHandle 메서드에는 a stringSomeResponseobject 라는 두 가지 인수가 있다고 가정 합니다.

var mock = new Mock<Handler>();
string stringResult = string.Empty;
SomeResponse someResponse = null;
mock.Setup(h => h.AsyncHandle(It.IsAny<string>(), It.IsAny<SomeResponse>()))
    .Callback<string, SomeResponse>((s, r) =>
    {
        stringResult = s;
        someResponse = r;
    });

// do your test
new Foo(mock.Object).Bar(22);
Assert.AreEqual("expected string", stringResult);
Assert.IsNotNull(someResponse);

기본적으로 It.IsAny<>()적절한 유형의 다른 유형을 추가하고 Callback메소드에 다른 유형을 추가 하고 람다 식을 적절하게 변경하면됩니다.


답변

콜백 메소드는 확실히 작동하지만 많은 매개 변수가있는 메소드 에서이 작업을 수행하는 경우 약간 장황 할 수 있습니다. 다음은 상용구를 제거하는 데 사용한 것입니다.

var mock = new Mock<Handler>();

// do your test   
new Foo(mock.Object).Bar(22);

var arg = new ArgumentCaptor<SomeResponse>();
mock.Verify(h => h.AsyncHandle(arg.Capture()));
Assert.NotNull(arg.Value);

ArgumentCaptor의 소스는 다음과 같습니다.

public class ArgumentCaptor<T>
{
    public T Capture()
    {
        return It.Is<T>(t => SaveValue(t));
    }

    private bool SaveValue(T t)
    {
        Value = t;
        return true;
    }

    public T Value { get; private set; }
}


답변

Gamlor의 답변은 효과가 있지만 그것을하는 또 다른 방법 (그리고 테스트에서보다 표현력이 있다고 생각되는 방법)은 …

var mock = new Mock<Handler>();
var desiredParam = 47; // this is what you want to be passed to AsyncHandle
new Foo(mock.Object).Bar(22);
mock.Verify(h => h.AsyncHandle(desiredParam), Times.Once());

확인은 매우 강력하며 익숙해지기 위해 시간을 할애 할 가치가 있습니다.


답변

대안은의 Capture.In기능 을 사용 하는 것 moq입니다. moq컬렉션에서 인수 캡처를 가능하게하는 것은 OOTB 기능입니다.

//Arrange
var args = new List<SomeResponse>();
mock.Setup(h => h.AnsyncHandle(Capture.In(args)));

//Act
new Foo(mock.Object).Bar(22);

//Assert
//... assert args.Single() or args.First()


답변

It.Is<TValue>()매처를 사용할 수 있습니다 .

var mock = new Mock<Handler>();
new Foo(mock.Object).Bar(22);
mock.Verify(h => h.AsyncHandle(It.Is<SomeResponse>(r => r != null )));


답변

이것은 또한 작동합니다 :

Mock<InterfaceThing> mockedObject = new Mock<InterfaceThing>();
var objectParameter = mockedObject.Invocations[1].Arguments[0] as ObjectParameter;