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


95

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

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

답변:


83

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

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

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

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

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

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

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

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

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


3
안녕하세요 Ruben 저는 Moq를 배우고 있습니다. 마음에 들면 Moq를 사용하여 작업을 수행하는 방법을 이해하기 위해 많은 예제를 작성하고 있습니다. 내 문제는 언제 그것을 사용 해야하는지 이해하지 못한다는 것입니다. 그 문제가 해결되면 나는 내 자신의 코드를 작성할 것입니다. 당신이 그것을 자신의 말로 설명한다면 언제 콜백을 사용합니까? 감사합니다. 시간을 내 주셔서 감사합니다
user9969

15
[링크]를 이기기가 어렵습니까? 전혀. 이 링크는 수십 가지의 다른 작업을 수행 하는 방법 을 보여 주지만 그 중 하나를 수행해야하는 이유 는 설명하지 않습니다 . 조롱 문서에서 흔히 볼 수있는 문제입니다. 나는 내가 찾은 TDD + 조롱에 대한 훌륭하고 명확한 설명의 수를 제로 손가락으로 믿을 수 있습니다. 대부분의 사람들은 내가 가지고 있다면 기사를 읽을 필요가없는 수준의 지식을 가정합니다.
Ryan Lundy 2011

@Kyralessa : 나는 당신의 요점을 받아들입니다. 나는 개인적으로 꽤 많은 책 지식이 들어 왔기 때문에 빠른 시작 항목이 절대적으로 완벽하다는 것을 알았습니다. 불행히도 나는 게시물 끝에 링크 한 더 나은 예를 알지 못합니다. 하나를 찾으면 여기에 게시 해 주시면 편집 해 드리겠습니다 (또는 DIY로 자유롭게)
Ruben Bartelink

"필요한 작업을 수행하고 반환 할 결과를 알려줄 것입니다 (있는 경우)"오해의 소지가 있다고 생각합니다. AFAIU Callback는 반환 값과 관련이 없습니다 (코드를 통해 링크하지 않는 한). 기본적으로 콜백이 각 호출 이전 또는 이후에 호출되는지 확인합니다 ( Returns각각 이전 또는 이후에 연결했는지 여부에 따라 다름 ), 단순하고 간단합니다.
오핫 슈나이더

1
@OhadSchneider 내 링크를 따라 ... 당신이 맞습니다! Fluent 인터페이스가 변경되었는지 여부 (하지만 Moq를 오랫동안 사용하지 않았기 때문에 충분히 관심이 없습니다) Fluent 인터페이스가 변경되었는지 여부 (예 : 잘못된 가정을하고 링크 된 내용을 읽지 못함) 자동 완성에서). 수정 주소에게 당신의 점을 희망, 그것은 나던 경우 알려 주시기
루벤 Bartelink

59

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

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");

4
(상태 또는 행동에 대한 테스트를 표현 하려는지 여부에 따라) 특정 경우에 대해 논란의 여지가 있지만, 어떤 경우 에는 테스트를 임시 It.Is<T>로 처리하는 Mock.Verify대신 in 을 사용하는 것이 더 깨끗할 수 있습니다. 하지만 +1은 예에서 가장 잘 작동하는 사람들이 많기 때문입니다.
Ruben Bartelink

10

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. 상황 별 상태 변경

2
실제로 두 가지 모두 호출이 반환되기 전에 발생합니다 (호출자에 관한 한). stackoverflow.com/a/28727099/67824를 참조하십시오 .
Ohad Schneider

5

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를 참조 하십시오 .


1

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.