[.net] Moq 콜백을 이해하도록 도와 주시겠습니까?

Moq를 사용하여 살펴 보았지만 Callback사용 방법을 이해하는 간단한 예제를 찾을 수 없었습니다.

사용 방법과시기를 명확하게 설명하는 작은 작업 스 니펫이 있습니까?



답변

이기기 어렵다 https://github.com/Moq/moq4/wiki/Quickstart

그것이 충분히 명확하지 않다면 나는 그것을 문서 버그라고 부를 것입니다.

편집 : 귀하의 설명에 대한 응답으로 …

Setup수행하는 각 모의 방법에 대해 다음과 같은 것을 나타냅니다.

  • 입력에 대한 제약
  • 반환 값 (있는 경우)이 파생되는 방법에 대한 값

.Callback메커니즘은 “나는 지금 그것을 설명 할 수는 없지만이 모양의 호출이 발생했을 때, 내가 다시 전화해서 내가 일을해야 일을 할 것이다”라고. 동일한 유창한 콜 체인의 일부로 .Returns” 를 통해 반환 할 결과 (있는 경우)를 제어 할 수 있습니다 . QS 예제에서 반환되는 값이 매번 증가하도록 만드는 것이 예입니다.

일반적으로 이와 같은 메커니즘은 자주 필요하지 않으며 (xUnit 테스트 패턴에는 테스트에서 ilk 조건부 논리의 반 패턴에 대한 용어가 있습니다) 필요한 것을 설정하는 더 간단하거나 내장 된 방법이 있다면 선호도에 사용됩니다.

Justin Etheredge의 Moq 시리즈 4 부 중 3 부에서 이를 다룹니다. 여기에 콜백의 또 다른 예가 있습니다.

콜백의 간단한 예는 Moq 게시물 에서 콜백 사용 에서 찾을 수 있습니다 .


답변

다음은 삽입을 처리하는 데이터 서비스에 전송 된 엔터티를 테스트하기 위해 콜백을 사용하는 예입니다.

var mock = new Mock<IDataService>();
DataEntity insertedEntity = null;

mock.Setup(x => x.Insert(It.IsAny<DataEntity>())).Returns(1) 
           .Callback((DataEntity de) => insertedEntity = de);

대체 일반 메서드 구문 :

mock.Setup(x => x.Insert(It.IsAny<DataEntity>())).Returns(1) 
           .Callback<DataEntity>(de => insertedEntity = de);

그런 다음 다음과 같은 것을 테스트 할 수 있습니다.

Assert.AreEqual("test", insertedEntity.Description, "Wrong Description");


답변

CallbackMoq 에는 두 가지 유형이 있습니다 . 호출이 반환되기 전에 하나가 발생합니다. 다른 하나는 호출이 반환 된 후에 발생합니다.

var message = "";
mock.Setup(foo => foo.Execute(arg1: "ping", arg2: "pong"))
    .Callback((x, y) =>
    {
        message = "Rally on!";
        Console.WriteLine($"args before returns {x} {y}");
    })
    .Returns(message) // Rally on!
    .Callback((x, y) =>
    {
        message = "Rally over!";
        Console.WriteLine("arg after returns {x} {y}");
    });

두 콜백 모두에서 다음을 수행 할 수 있습니다.

  1. 메서드 인수 검사
  2. 캡처 메서드 인수
  3. 상황 별 상태 변경

답변

Callback모의 메소드 중 하나를 호출 할 때 원하는 사용자 정의 코드를 실행하는 수단 일뿐입니다. 다음은 간단한 예입니다.

public interface IFoo
{
    int Bar(bool b);
}

var mock = new Mock<IFoo>();

mock.Setup(mc => mc.Bar(It.IsAny<bool>()))
    .Callback<bool>(b => Console.WriteLine("Bar called with: " + b))
    .Returns(42);

var ret = mock.Object.Bar(true);
Console.WriteLine("Result: " + ret);

// output:
// Bar called with: True
// Result: 42

최근에 흥미로운 사용 사례를 접했습니다. 모의에 대한 일부 호출을 예상하지만 동시에 발생한다고 가정합니다. 따라서 호출되는 순서를 알 수있는 방법이 없지만 예상 한 호출이 (순서에 관계없이) 발생했는지 알고 싶습니다. 다음과 같이 할 수 있습니다.

var cq = new ConcurrentQueue<bool>();
mock.Setup(f => f.Bar(It.IsAny<bool>())).Callback<bool>(cq.Enqueue);
Parallel.Invoke(() => mock.Object.Bar(true), () => mock.Object.Bar(false));
Console.WriteLine("Invocations: " + String.Join(", ", cq));

// output:
// Invocations: True, False

BTW는 오해의 소지가있는 “이전 Returns“과 “이후 Returns“구분으로 혼동하지 않습니다 . 사용자 지정 코드가 Returns평가 된 후 또는 이전에 실행되는지 여부에 대한 기술적 인 차이 일뿐 입니다. 호출자의 눈에는 값이 반환되기 전에 둘 다 실행됩니다. 실제로 메서드가 void-returning이면 호출조차 할 수 없지만 여전히 Returns동일하게 작동합니다. 자세한 내용은 https://stackoverflow.com/a/28727099/67824를 참조 하십시오 .


답변

여기에 다른 좋은 답변 외에도 예외를 던지기 전에 논리를 수행하는 데 사용했습니다. 예를 들어, 나중에 확인하기 위해 메서드에 전달 된 모든 개체를 저장해야했고 해당 메서드 (일부 테스트 사례에서)는 예외를 throw해야했습니다. 호출 은 작업 .Throws(...)Mock.Setup(...)무시하고 Callback()호출하지 않습니다. 그러나 콜백 내에서 예외를 throw하면 콜백이 제공해야하는 모든 좋은 작업을 수행 할 수 있으며 여전히 예외를 throw 할 수 있습니다.


답변