Programming

Moq로 특정 매개 변수 확인

procodes 2020. 6. 13. 20:08
반응형

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의 버그에 유의하십시오. 그들은 지금까지 그것을 고쳤을 것입니다. 그러나 만약 당신이 그 메시지를 보게되면 당신은 메소드가 실제로 호출되었는지 확인하는 것을 고려할 것입니다.

EDIT: Here is an example of calling verify multiple times for those scenarios where you want to verify that you call a function for each object in a list (for example).

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

Same approach for setup...

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

So each time GetStuff is called for that itemId, it will return stuff specific to that item. Alternatively, you could use a function that takes itemId as input and returns stuff.

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

One other method I saw on a blog some time back (Phil Haack perhaps?) had setup returning from some kind of dequeue object - each time the function was called it would pull an item from a queue.


A simpler way would be to do:

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

I believe that the problem in the fact that Moq will check for equality. And, since XmlElement does not override Equals, it's implementation will check for reference equality.

Can't you use a custom object, so you can override equals?


Had one of these as well, but the parameter of the action was an interface with no public properties. Ended up using It.Is() with a seperate method and within this method had to do some mocking of the interface

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
}

참고URL : https://stackoverflow.com/questions/4956974/verifying-a-specific-parameter-with-moq

반응형