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.

Nicholas Murray
quelle

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";
}
Ufuk Hacıoğulları
quelle
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 */);
cadrell0
quelle
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>(...).

Bartosz
quelle
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");
Jaider
quelle
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