2016-09-09 1 views
2

Ich versuche, über die Verwendung von Moq mit NUnit und IoC zu lernen.Den Daten Accessor ausspionieren

(Ich habe mein ganzes Projekt in BitBucket, aber nicht sicher, wie es zu teilen ...) https://bitbucket.org/Cralis/skeleton/overview

Ich habe eine Logic-Methode (Login) I zu testen, versuchen. Es braucht ein Anfrageobjekt (welches einen Benutzernamen, ein Passwort und eine IP-Adresse hat). Wenn der Benutzername und/oder das Kennwort leer sind, gibt die Logik einen Fehlerstatus zurück und geht nicht zur Datenzugriffsebene.

Also ich erstellen einen Komponententest, um dies zu testen. (Das ist mein mein erster Versuch mit spöttischen ...)

public void NotNull_Returns_True() 
     { 
      // Arrange 
      var request = new LoginRequest { IPAddress = "1.1.1.1", Username = "dummy", Password = "dummy" }; 
      var response = new LoginResponse { Request = request, Success = true, Message = "", UserID = 1 }; 

      // Setup the moc data accessor, as we don't want to gop to the concrete one. 
      var MockedDataAccess = new Mock<IDataAccess>(); 

      // Set it's return value 
      MockedDataAccess.Setup(x => x.Login(request)).Returns(response); 

      // Instantiate the Logic class we're testing, using a Moc data accessor. 
      var logic = new BusinessLogic(MockedDataAccess.Object); 

      // Act 
      var result = logic.Login(new LoginRequest { Password = "dummy", Username = "dummy", IPAddress = "1.1.1.1" }); 

      // Assert 
      Assert.AreEqual(true, result.Success); 
     } 

Dies scheitert auf dem assert, als 'Ergebnis' ist NULL.

Ich mache wahrscheinlich viel falsch. Zum Beispiel bin ich mir nicht sicher, warum ich die Request- und Response-Objekte oben einrichten muss, aber da alle Beispiele, die ich finde, 'string' und 'int' Inputs sind, scheint es, dass ich It.IsAny nicht verwenden kann. ..

Könnte jemand mir helfen, hier zu verstehen? Was mache ich falsch, um NULL als Ergebnis in der Assert zu bekommen? Ich gehe durch und der Code wird wie erwartet ausgeführt. Aber das Ergebnis ist null, weil ich nie den Datenzugriffsmechanismus aufgerufen habe (es hat den Mock verwendet).

Edit: Ah,

// Set it's return value 
      MockedDataAccess.Setup(x => x.Login(It.IsAny<LoginRequest>())).Returns(response); 

dass das Problem behoben. Ich bin mir nicht sicher, warum, also wenn Sie mir helfen können, dies zu verstehen und zu überarbeiten, so dass es so ist, wie es ein erfahrener Moq/UnitTester erwartet hätte, wäre das sehr nützlich.

+0

Was ist Ihr 'Login' Methode tun? Ruft es Methoden für Ihre IDataAccess-Abhängigkeit auf und gibt null zurück, wenn diese Methoden null zurückgeben? –

+0

@BenRubin - Ich habe einen Bitbucket-Link hinzugefügt, damit Sie alles sehen und klonen können. Wenn jedoch Nullwerte an die BL-Schicht gesendet werden, wird ein Response-Objekt ausgewertet und zurückgegeben, wobei das Erfolgsflag den Wert False hat. Es sollte niemals ein Null-Objekt zurückgeben. – Craig

Antwort

3

Auch wenn Ihr request Objekt die gleichen Eigenschaftswerte hat, die Sie var result = logic.Login(new LoginRequest { Password = "dummy", Username = "dummy", IPAddress = "1.1.1.1" }); vorbei sind, sind sie verschiedene Objekte, so dass der Wert, den Sie mit MockedDataAccess.Setup(x => x.Login(request)).Returns(response); zurückkehren möchten, ist nicht zurückgeschickt zu werden.

ändern

var result = logic.Login(new LoginRequest { Password = "dummy", Username = "dummy", IPAddress = "1.1.1.1" }); 

zu

var result = logic.Login(request); 

Der Grund ist es mit MockedDataAccess.Setup(x => x.Login(It.IsAny<LoginRequest>())).Returns(response); gearbeitet ist, weil jetzt bist du sagen „, wenn MockedDataAccess.Login mit jeder Wert für seine Parameter aufgerufen wird, kehren response "

In Bezug auf den zweiten Teil Ihrer Frage besteht der Grund, warum Sie die Request- und Response-Objekte einrichten müssen, darin, dass jede Methode, die Sie für ein Mock-Objekt aufrufen, standardmäßig null zurückgibt. Ihre BusinessLogic.Login Methode, die unten aufgeführt ist, wird den Wert dataAccess.Login() zurückgeben. Da dataAccess ein Mock ist, gibt die dataAccess.Login()-Methode null zurück, es sei denn, Sie geben etwas anderes an.

public LoginResponse Login(LoginRequest request) 
    { 

     // Basic validation 
     if (request == null) 
      return new LoginResponse 
      { 
       Success = false, 
       Message = "Empty Request" 
      }; 

     if (string.IsNullOrEmpty(request.Username) || string.IsNullOrEmpty(request.Password)) 
      return new LoginResponse 
      { 
       Success = false, 
       Message = "Username and/or password empty" 
      }; 

     // This is returning null since dataAccess is a mock 
     return dataAccess.Login(request); 
    } 

Sie sagten, Sie denken, dass Sie eine Menge falsch machen, aber die Art und Weise Sie den Test ist so ziemlich eingerichtet haben, was ich tue. Das einzige, was ich ändern würde (zusätzlich zu der Setup Methode, wie oben beschrieben) zu beheben, ist die Verwendung des UnitOfWork_StateUnderTest_ExpectedBehavior Namensmuster für Ihren Test.Zum Beispiel Login_ValidLoginRequest_ShouldReturnValidLoginResponse()

+0

Danke @BenRubin - Das alles macht viel Sinn und hilft mir auf meinem Lernweg und bietet eine gewisse Validierung. Vielen Dank. – Craig

2

Das Problem mit diesem Code

var result = logic.Login(new LoginRequest { Password = "dummy", Username = "dummy", IPAddress = "1.1.1.1" })

ist, dass bei der Umsetzung der Login Methode dieses

dataAccess.Login(request)

heißt es bedeutet, dass Sie Setup das Mock von DataAccess für Methode Login weil Mock sonst nichts tut. Mock wenn gefälschte und muss so eingerichtet sein, dass es so funktioniert, wie Sie brauchen. In diesem Fall ist die Antwort von @Ben Rubin absolut richtig.

Wenn Mock Setup wie dieses

MockedDataAccess.Setup(x => x.Login(request)).Returns(response)

ist, dann ist es notwendig, die Methode im Test mit genau dem gleichen Request-Objekt wie die Anforderung zu nennen, die im Setup des Datenzugriffs Login Methode verwendet wurden, weil Andernfalls wird der Schein als nicht eingerichtet fungieren. Hier heißt es im Wesentlichen: 'Wenn DataAccess Login mit genau dieser Anfrage aufgerufen wird, wird diese Antwort zurückgegeben'.

Aber als Mock-Setup wie dieses

MockedDataAccess.Setup(x => x.Login(It.IsAny<LoginRequest>())).Returns(response)

ist dann funktioniert es, weil hier Login ist Setup zu jedem LoginRequest. Also wird der Schein in diesem Fall response zurückgeben, egal welche Anfrage verwendet wurde.

HTH

Hier sind weitere Informationen über Mock Matching Arguments

Verwandte Themen