[C#] Moq로 특정 매개 변수 확인

public void SubmitMessagesToQueue_OneMessage_SubmitSuccessfully()
{
    var messageServiceClientMock = new Mock<IMessageServiceClient>();
    var queueableMessage = CreateSingleQueueableMessage();
    var message = queueableMessage[0];
    var xml = QueueableMessageAsXml(queueableMessage);
    messageServiceClientMock.Setup(proxy => proxy.SubmitMessage(xml)).Verifiable();
    //messageServiceClientMock.Setup(proxy => proxy.SubmitMessage(It.IsAny<XmlElement>())).Verifiable();

    var serviceProxyFactoryStub = new Mock<IMessageServiceClientFactory>();
    serviceProxyFactoryStub.Setup(proxyFactory => proxyFactory.CreateProxy()).Returns(essageServiceClientMock.Object);
    var loggerStub = new Mock<ILogger>();

    var client = new MessageClient(serviceProxyFactoryStub.Object, loggerStub.Object);
    client.SubmitMessagesToQueue(new List<IMessageRequestDTO> {message});

    //messageServiceClientMock.Verify(proxy => proxy.SubmitMessage(xml), Times.Once());
    messageServiceClientMock.Verify();
}

나는 Moq를 사용하기 시작하고 조금 어려움을 겪고 있습니다. messageServiceClient가 올바른 매개 변수 (XmlElement)를 수신하고 있는지 확인하려고하지만 작동시킬 방법을 찾을 수 없습니다. 특정 값을 확인하지 않은 경우에만 작동합니다.

어떤 아이디어?

부분 답변 : 프록시로 전송 된 xml이 올바른지 테스트하는 방법을 찾았지만 여전히 올바른 방법이라고 생각하지 않습니다.

public void SubmitMessagesToQueue_OneMessage_SubmitSuccessfully()
{
    var messageServiceClientMock = new Mock<IMessageServiceClient>();
    messageServiceClientMock.Setup(proxy => proxy.SubmitMessage(It.IsAny<XmlElement>())).Verifiable();
    var serviceProxyFactoryStub = new Mock<IMessageServiceClientFactory>();
    serviceProxyFactoryStub.Setup(proxyFactory => proxyFactory.CreateProxy()).Returns(messageServiceClientMock.Object);
    var loggerStub = new Mock<ILogger>();

    var client = new MessageClient(serviceProxyFactoryStub.Object, loggerStub.Object);
    var message = CreateMessage();
    client.SubmitMessagesToQueue(new List<IMessageRequestDTO> {message});

    messageServiceClientMock.Verify(proxy => proxy.SubmitMessage(It.Is<XmlElement>(xmlElement => XMLDeserializer<QueueableMessage>.Deserialize(xmlElement).Messages.Contains(message))), Times.Once());
}

그런데 Verify 호출에서 식을 어떻게 추출 할 수 있습니까?



답변

검증 로직이 사소한 것이 아니라면 (예에서 보듯이) 큰 람다 방법을 작성하는 것이 지저분합니다. 모든 테스트 문을 별도의 방법으로 넣을 수는 있지만 테스트 코드 읽기 흐름을 방해하기 때문에 이것을 좋아하지 않습니다.

또 다른 옵션은 Setup 호출에서 콜백을 사용하여 모의 메소드에 전달 된 값을 저장 한 다음 표준 Assert메소드를 작성 하여이를 검증하는 것입니다. 예를 들면 다음과 같습니다.

// Arrange
MyObject saveObject;
mock.Setup(c => c.Method(It.IsAny<int>(), It.IsAny<MyObject>()))
        .Callback<int, MyObject>((i, obj) => saveObject = obj)
        .Returns("xyzzy");

// Act
// ...

// Assert
// Verify Method was called once only
mock.Verify(c => c.Method(It.IsAny<int>(), It.IsAny<MyObject>()), Times.Once());
// Assert about saveObject
Assert.That(saveObject.TheProperty, Is.EqualTo(2));


답변

같은 방식으로 전화를 확인하고 있습니다. 전화를하는 것이 올바른 방법이라고 생각합니다.

mockSomething.Verify(ms => ms.Method(
    It.IsAny<int>(),
    It.Is<MyObject>(mo => mo.Id == 5 && mo.description == "test")
  ), Times.Once());

람다식이 다루기 어려워지면 MyObject입력 및 출력으로 사용되는 함수를 만들 수 있습니다 true/ false

mockSomething.Verify(ms => ms.Method(
    It.IsAny<int>(),
    It.Is<MyObject>(mo => MyObjectFunc(mo))
  ), Times.Once());

private bool MyObjectFunc(MyObject myObject)
{
  return myObject.Id == 5 && myObject.description == "test";
}

또한 메소드가 호출되지 않았을 때 메소드가 여러 번 호출되었다는 오류 메시지가 표시되는 Mock의 버그에 유의하십시오. 그들은 지금까지 그것을 고쳤을 것입니다. 그러나 당신이 그 메시지를 보게되면 메소드가 실제로 호출되었는지 확인하는 것을 고려할 수 있습니다.

편집 : 다음은 목록의 각 객체에 대해 함수를 호출하는지 확인하려는 시나리오에서 여러 번 확인을 호출하는 예입니다 (예 :).

foreach (var item in myList)
  mockRepository.Verify(mr => mr.Update(
    It.Is<MyObject>(i => i.Id == item.Id && i.LastUpdated == item.LastUpdated),
    Times.Once());

동일한 설정 방법 …

foreach (var item in myList) {
  var stuff = ... // some result specific to the item
  this.mockRepository
    .Setup(mr => mr.GetStuff(item.itemId))
    .Returns(stuff);
}

따라서 해당 itemId에 대해 GetStuff가 호출 될 때마다 해당 항목에 특정한 항목을 반환합니다. 또는 itemId를 입력으로 받아서 물건을 반환하는 함수를 사용할 수 있습니다.

this.mockRepository
    .Setup(mr => mr.GetStuff(It.IsAny<int>()))
    .Returns((int id) => SomeFunctionThatReturnsStuff(id));

필자가 언젠가 블로그에서 보았던 다른 방법 (Phil Haack?)은 일종의 dequeue 객체에서 돌아 오는 설정을 가지고 있습니다. 함수가 호출 될 때마다 대기열에서 항목을 가져옵니다.


답변

더 간단한 방법은 다음과 같습니다.

ObjectA.Verify(
    a => a.Execute(
        It.Is<Params>(p => p.Id == 7)
    )
);


답변

나는 Moq가 평등을 점검한다는 사실의 문제를 믿는다. 그리고 XmlElement는 Equals를 재정의하지 않기 때문에 구현시 참조 동등성을 검사합니다.

맞춤 객체를 사용할 수 없어서 등호를 재정의 할 수 있습니까?


답변

이것들 중 하나도 있었지만 액션의 매개 변수는 공용 속성이없는 인터페이스였습니다. 별도의 메소드와 함께 It.Is ()를 사용하여 종료 되었으며이 메소드 내에서 인터페이스를 조롱해야했습니다.

public interface IQuery
{
    IQuery SetSomeFields(string info);
}

void DoSomeQuerying(Action<IQuery> queryThing);

mockedObject.Setup(m => m.DoSomeQuerying(It.Is<Action<IQuery>>(q => MyCheckingMethod(q)));

private bool MyCheckingMethod(Action<IQuery> queryAction)
{
    var mockQuery = new Mock<IQuery>();
    mockQuery.Setup(m => m.SetSomeFields(It.Is<string>(s => s.MeetsSomeCondition())
    queryAction.Invoke(mockQuery.Object);
    mockQuery.Verify(m => m.SetSomeFields(It.Is<string>(s => s.MeetsSomeCondition(), Times.Once)
    return true
}


답변