Mehrere Moq It.Is <string> () übereinstimmende Argumente


76

Ist es bei Moq gültig, mehr als ein Übereinstimmungsargument zu haben?

It.Is<string>() 

In diesem Beispiel möchte ich, dass der mockMembershipService je nach angegebenem Benutzer einen anderen ProviderUserKey zurückgibt.

mockMembershipService.Setup(
    x => x.GetUser(
      It.Is<string>(
        s => s.Contains("Joe")))
   .ProviderUserKey)
.Returns("1234abcd");


mockMembershipService.Setup(
  x => x.GetUser(
    It.Is<string>(
      s => s.Contains("Tracy")))
  .ProviderUserKey)
.Returns("5678efgh");

Das SetUp verwendet standardmäßig die zweite Anweisung, anstatt jede für sich zu bewerten.

Antworten:


54

Ist es nicht verwirrend? Sie versuchen, die GetUser-Methode zu verspotten, legen jedoch die Rückgabe für die Rückgabewert-Eigenschaft dieser Funktion fest. Sie möchten auch die Eigenschaft des Rückgabetyps basierend auf der verspotteten Methode angeben.

Hier ist ein klarerer Weg:

mockMembershipService.Setup(x => x.GetUser(It.IsAny<string>())
                     .Returns<string>(GetMembershipUser);

Hier ist eine Methode zum Erstellen des Mitgliedschaftsmodells:

private MembershipUser GetMembershipUser(string s)
{
    Mock<MembershipUser> user =new Mock<MembershipUser>();
    user.Setup(item => item.ProviderUserKey).Returns(GetProperty(s));
    return user.Object;
}

Dann schreiben Sie eine Methode zum Festlegen dieser Eigenschaft:

private string GetProperty(string s)
{
    if(s.Contains("Joe"))
        return "1234abcd";
    else if(s.Contains("Tracy"))
        return "5678efgh";
}

1
Werde dies in Kürze versuchen, habe mir dieses Video angesehen, thethoughtfulcoder.com/blog/52/…, während du deine Antwort hinzugefügt hast, die etwas Ähnliches bewirkt
Nicholas Murray

Der obige Code wird nicht kompiliert. Er beschwert sich über Security.MembershipUser enthält keine Referenz für Rücksendungen und auch über Benutzer, die keine Definition für ProviderUserKey enthalten
Nicholas Murray

Sie sollten auf die Assembly verweisen, die Security.MembershipUser enthält, denke ich. Oder Sie können eine Abhängigkeit für das Erstellen von Benutzern für Sie in Ihren MembershipService
Ufuk Hacıoğulları

hmmm - es beschwert sich nicht darüber, wenn ich mich versuche - (was natürlich nicht wie gewünscht funktioniert)
Nicholas Murray

Ich denke, Sie können eine andere Funktion schreiben, um ein MembershipUser-Modell zu erstellen, aber es gerät ernsthaft außer Kontrolle. Ich habe den Code aktualisiert.
Ufuk Hacıoğulları

33

Wenn Sie die Eingabe auf "Joe" und "Tracy" beschränken möchten, können Sie in mehrere Bedingungen angeben It.Is<T>(). Etwas wie

mockMembershipService.Setup(x => x.GetUser(It.Is<String>(s => s.Contains("Joe") 
                                                         || s.Contains("Tracy")))
    .Returns<string>(/* Either Bartosz's or Ufuk's answer */);

Es ist nicht so, dass ich per se einschränken möchte, ich möchte nur die Eingabe bewerten und die gewünschte Ausgabe zurückgeben :-)
Nicholas Murray

Unabhängig davon, ob dies an der richtigen Stelle war, hat es mir geholfen, danke @ cadrell0
Jacob McKay

15

Aufeinanderfolgende Setup-Aufrufe machen frühere Setups ungültig.

Sie könnten Ihr Argument in Ihrem Rückruf verwenden:

mockMembershipService.Setup(x => x.GetUser(It.IsAny<string>()).ProviderUserKey).Returns<string>(s =>
{
    if(s.Contains("Joe"))
        return "1234abcd";
    else if(s.Contains("Tracy"))
        return "5678efgh";
});

Wenn es Ihnen wichtig ist, das übergebene Argument zu behaupten, müssen Sie It.Is<string>(...)stattdessen statt It.IsAny<string>(...).


Ich sollte das in ungefähr 2 Stunden ausprobieren können.
Nicholas Murray

Na ja, ich denke, das liegt daran, dass wir hier eine Immobilie einrichten ( ProviderUserKey), während das Argument, auf das wir reagieren wollen, von kommt GetUser(...). Ich kann momentan nicht die richtige Lösung überprüfen, aber wenn Sie den Ratschlägen von Ufuk folgen, sollte es in Ordnung sein ...
Bartosz

Ich werde es über das Wochenende versuchen - danke für Ihre Hilfe! Nicht so einfach wie ich zuerst dachte.
Nicholas Murray

@ Mattumotu: Das ist nicht das, was ich erlebe, Moq hat nur eine seltsame Ausführungsrichtlinie. Später hinzugefügte Setup-Aufrufe werden zuerst ausgewertet (oder es werden immer alle ausgewertet und zuletzt gewonnen). Es ist genau das Gegenteil von dem, was man erwarten würde: Normalerweise wird das erste Match zurückgegeben und der Rest wird ignoriert.
Christoph

6

Bitte überprüfen Sie die Dokumentation zu Einführung in Moq> Übereinstimmende Argumente :

// matching Func<int>, lazy evaluated
mock.Setup(foo => foo.Add(It.Is<int>(i => i % 2 == 0))).Returns(true); 


// matching ranges
mock.Setup(foo => foo.Add(It.IsInRange<int>(0, 10, Range.Inclusive))).Returns(true); 


// matching regex
mock.Setup(x => x.DoSomething(It.IsRegex("[a-d]+", RegexOptions.IgnoreCase))).Returns("foo");

3
Mit mehr Erfahrung in Unit Tests empfehle ich diesen Ansatz nicht. Wir sollten vermeiden, Logik in die Unit-Tests aufzunehmen. Eine andere Option ist das Erstellen separater
Jaider
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.