2016-06-20 8 views
0

Aufgrund dieser FunktionsreferenzMoq: Werte zurück von ref Parameter in Test

bekommen
void ParseFirstTwoRows(FileQueue file, ref string[] firstRow, ref string[] secondRow); 

Wie kann ich Moq verwenden, um einen Test zu gestalten, die einen Wert auf firstrow und secondRow mit verlässt sich?

Ich habe dies versucht:

Mock<IFileParser> mockFileParse = new Mock<IFileParser>(); 

string[] firstline = new string[2] { "1", "2" }; 
string[] secondline = null; 

mockFileParse.Setup(m => m.ParseFirstTwoRows(It.IsAny<FileQueue>(), ref firstline, ref secondline)) 
       .Callback<FileQueue, string[], string[]>((fq, fl, sl) => 
       { 
        fq = new FileQueue(); 
        fl = firstline; 
        sl = secondline; 
       }); 

return mockFileParse; 

Aber dies führt zu dem Fehler:

Invalid callback. Setup on method with parameters (FileQueue,String[]&,String[]&) cannot invoke callback with parameters (FileQueue,String[],String[]).

ich einige Fragen zu diesem Thema gesehen habe, aber ich bin verwirrt, ob das, was ich bin zu versuchen ist unmöglich, oder ob ich den Test nicht richtig einrichte. Alles, was ich für meine Tests brauche, ist sicherzustellen, dass die ref-Parameter einen Wert im ausführenden Code haben.

Antwort

0

Ich löste dies, indem ich einige Refactoring. Moq bietet keine Unterstützung für Ref-Parameter in diesem Szenario, aber es funktioniert mit Out-Parametern.

Hier ist die Refactoring-Funktion Unterschrift:

void ParseFirstTwoRows(FileQueue file, out string[] firstRow, out string[] secondRow); 

Und hier ist der Testaufbau:

string[] first = { "'one'", "'two'", "'three'" }; 
string[] second = { "'one'", "'two'", "'three'" }; 

Mock<IFileParser> mockFileParse = new Mock<IFileParser>(); 
mockFileParse.Setup(m => m.ParseFirstTwoRows(It.IsAny<FileQueue>(), out first, out second)).Verifiable(); 

Nun, wenn Sie eine Funktion versuchen und testen, die das Mock die beiden angegebenen Variablen liefern auf ParseFirstTwoRows hängt für die out Parameter.

0

Sie müssen den Rückruf nicht ausführen. Stellen Sie nur sicher, dass der Aufruf fehlschlägt, wenn Sie Ihr SUT aufrufen, dass Sie die gleichen Ref-Argumente verwenden.

am folgende Beispiel einen Blick Nehmen Sie Beispielcode als Referenz

[TestClass] 
public class FileParserTest : MiscMoqTests { 
    [TestMethod] 
    public void Moq_With_Ref_Arguents() { 
     //Arrange 
     Mock<IFileParser> mockFileParse = new Mock<IFileParser>(); 
     // ref arguments 
     string[] firstline = new string[2] { "1", "2" }; 
     string[] secondline = null; 
     // Only matches if the ref arguments to the invocation are the same instance 
     mockFileParse.Setup(m => m.ParseFirstTwoRows(It.IsAny<FileQueue>(), ref firstline, ref secondline)).Verifiable(); 

     var sut = new MyDummyClass(mockFileParse.Object); 

     //Act 
     sut.DoSomethingWithRef(ref firstline, ref secondline); 

     //Assert 
     mockFileParse.Verify(); 
    } 

    public class MyDummyClass { 
     private IFileParser fileParser; 

     public MyDummyClass(IFileParser fileParser) { 
      this.fileParser = fileParser; 
     } 

     public void DoSomethingWithRef(ref string[] firstRow, ref string[] secondRow) { 
      var fq = new FileQueue(); 
      fileParser.ParseFirstTwoRows(fq, ref firstRow, ref secondRow); 

     } 
    } 

    public interface IFileParser { 
     void ParseFirstTwoRows(FileQueue file, ref string[] firstRow, ref string[] secondRow); 
    } 
    public class FileQueue { } 
} 

Wenn Sie jedoch nicht in der Lage sind die gleichen Instanzen für den ref liefern es so aussehen wie Sie dann nicht in der Lage sein werden, Erhalten Sie einen Schein, um erfolgreich zu bestehen. Werfen Sie einen Blick auf die Quick Start for Moq, um ein Verständnis für die Fähigkeiten zu bekommen.

+0

Dank für diese, aber der Anruf mit ref ist eine private Funktion namens von eine öffentliche, also kann ich die params nicht so passieren. Daher mein Problem. –

+0

In diesem Fall würde ich vorschlagen, für diesen Test manuell einen eigenen Mock zu erstellen und auf Moq für diese Schnittstelle zu verzichten. – Nkosi

0

Ich sah, dass Sie Ihr Problem gelöst haben, indem Sie out-Parameter anstelle von Ref-Parameter verwenden.

Aber Ihre Produktion Code zu ändern ist nicht die Lösung, können Sie Typemock Isolator verwendet werden, die einen Test mit ref Parameter erstellen können:

[TestMethod,Isolated] 
public void Mocking_With_Ref_Arguments() 
{ 
    // Arrange 
    string[] first = { "'one'", "'two'", "'three'" }; 
    string[] second = { "'one'", "'two'", "'three'" }; 
    FileQueue file = new FileQueue(); 
    var classUnderTest = new Class1(); 

    // What you will set as ref parameters in this line will return as you call the method 
    Isolate.WhenCalled(() => classUnderTest.ParseFirstTwoRows(file, ref first, ref second)).IgnoreCall(); 

    // Act 
    string[] retFirst = null; 
    string[] retSecond = null; 
    classUnderTest.someMethod(file, ref retFirst, ref retSecond); 

    // Assert 
    CollectionAssert.AreEquivalent(first, retFirst); 
    CollectionAssert.AreEquivalent(second, retSecond); 
} 
Verwandte Themen