it-swarm.com.de

Bestimmen eines bestimmten Parameters mit 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();
}

Ich beginne mit Moq und versuche ein wenig zu kämpfen ... Ich versuche zu überprüfen, dass messageServiceClient den richtigen Parameter empfängt, der ein XmlElement ist, aber ich finde keinen Weg, damit es funktioniert. Es funktioniert nur, wenn ich einen bestimmten Wert nicht überprüfe.

Irgendwelche Ideen?

Teilweise Antwort: Ich habe einen Weg gefunden, um zu testen, ob die an den Proxy gesendete XML-Datei korrekt ist, aber ich denke immer noch nicht, dass dies der richtige Weg ist.

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());
}

Wie könnte ich übrigens den Ausdruck aus dem Verify-Aufruf extrahieren?

123
Luis Mirabal

Wenn die Überprüfungslogik nicht trivial ist, ist es unordentlich, eine große Lambda-Methode zu schreiben (wie Ihr Beispiel zeigt). Sie können alle Testanweisungen in eine separate Methode schreiben, aber ich mag das nicht, weil dies den Ablauf des Lesens des Testcodes stört. 

Eine andere Option besteht darin, einen Rückruf für den Setup-Aufruf zu verwenden, um den Wert zu speichern, der an die übermittelte Methode übergeben wurde, und dann die Assert-Standardmethoden zu schreiben, um sie zu überprüfen. Zum Beispiel:

// 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));
192
Rich Tebb

Ich habe Anrufe auf dieselbe Weise überprüft - ich glaube, dass dies der richtige Weg ist.

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

Wenn Ihr Lambda-Ausdruck unhandlich wird, können Sie eine Funktion erstellen, die MyObject als Eingabe und Ausgänge true/false... verwendet.

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

Beachten Sie außerdem einen Fehler bei Mock, bei dem in der Fehlermeldung angegeben wird, dass die Methode mehrmals aufgerufen wurde, als sie überhaupt nicht aufgerufen wurde. Sie haben es vielleicht schon behoben - aber wenn Sie diese Nachricht sehen, können Sie prüfen, ob die Methode tatsächlich aufgerufen wurde.

BEARBEITEN: Hier ein Beispiel für den mehrfachen Aufruf von verify für die Szenarien, in denen Sie überprüfen möchten, dass Sie für jedes Objekt in einer Liste eine Funktion aufrufen (beispielsweise).

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

Gleicher Ansatz für das Setup ...

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

Jedes Mal, wenn GetStuff für diese itemId aufgerufen wird, gibt es spezifische Elemente für diesen Artikel zurück. Alternativ können Sie eine Funktion verwenden, die itemId als Eingabe übernimmt und Zeugs zurückgibt.

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

Eine andere Methode, die ich vor einiger Zeit in einem Blog (Phil Haack?.

69
Mayo

Ein einfacherer Weg wäre zu tun:

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

Ich glaube, dass das Problem darin liegt, dass Moq auf Gleichheit überprüft wird. Da XmlElement Equals nicht überschreibt, wird die Implementierung auf Referenzgleichheit geprüft. 

Können Sie kein benutzerdefiniertes Objekt verwenden, damit Sie Gleichgestellte überschreiben können?

1
Fernando

Hatte auch eine davon, aber der Parameter der Aktion war eine Schnittstelle ohne öffentliche Eigenschaften. Endete mit It.Is () mit einer separaten Methode und innerhalb dieser Methode musste die Schnittstelle ein wenig gespielt werden

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
}
0
ds4940