2015-04-17 13 views
7

Ich möchte moq eine Eigenschaft, die einen Index hat, und ich möchte in der Lage sein, die Indexwerte im Rückruf zu verwenden, auf die gleiche Weise können Sie Methode verwenden Argumente im Callback für moq'd-Methoden. Wahrscheinlich am einfachsten mit einem Beispiel demonstrieren:Moq eine indizierte Eigenschaft und verwenden Sie den Index-Wert in der Rückkehr/Rückruf

public interface IToMoq 
{ 
    int Add(int x, int y); 
    int this[int x] { get; set; } 
} 

    Action<int, int> DoSet = (int x, int y) => 
    { 
     Console.WriteLine("setting this[{0}] = {1}", x, y); 
     throw new Exception("Do I ever get called?"); 
    }; 
    var mock = new Mock<IToMoq>(MockBehavior.Strict); 

    //This works perfectly 
    mock.Setup(m => m.Add(It.IsAny<int>(), It.IsAny<int>())) 
     .Returns<int, int>((a, b) => a + b); 

    //This compiles, but my callback never seems to be called 
    mock.SetupSet(m => m[It.IsAny<int>()] = It.IsAny<int>()) 
     .Callback(DoSet); 

    var obj = mock.Object; 
    Console.WriteLine("Add(3,4) => {0}", obj.Add(3, 4)); //Works perfectly 
    obj[1] = 2; //Does not throw, why? 

Edit: Um zu klären, mag ich die Rückruf/Returns Methode zum getFunc<int,int> sein, und die Rückruf/Returns Methode zum setAction<int,int> sein. Der Versuch, was Mike vorgeschlagen, können Sie Art, dies zu tun für set, aber mit einer großen Einschränkung:

mock.SetupSet(m => m[23] = It.IsAny<int>()) 
      .Callback(DoSet).Verifiable(); 

Der Rückruf DoSet in der Tat wird dann mit Werten (23,<any>) genannt. Leider It.IsAny<int>() statt 23 scheint sich als 0 statt <any> zu verhalten.

Auch konnte ich nicht einen Weg finden SetupGet mit Returns Aufruf wo Returns eine Func<int,int> nimmt, die selbst zusammenstellen würde.

Ist es möglich, Moq dafür zu verwenden?

Motivation: Ich spiele gerade mit Moq, versuchend, es zu benutzen, um eine fließende API für das Abfangen zur Verfügung zu stellen. Das bedeutet, dass bei einer Schnittstelle I und einer Instanz X von I automatisch ein Mock<I>-Proxy mit einem Verhalten von X erstellt wird.

Wäre wahrscheinlich sinnvoller, direkt mit Castle DP zu arbeiten, aber ich mag die Moq Expression Tree-Syntax.

+0

Scheint wie ein Fehler für mich. Einrichten des Mocks mit 'mock.SetupSet (c => c [1] = It.IsAny ()). Callback (DoSet);' funktioniert wie erwartet, 'mock.SetupSet (c => c [It.IsAny ()] = It.IsAny ()) .Rückruf (DoSet); 'schlägt mit' MockBehavior.Strict' fehl und tut nichts mit 'MockBehavior.Loose'. – sloth

+0

Mit 'mock.SetupSet (x => x [It.IsAny ()] = It.IsAny ()) .Rückruf (doSet);' und 'obj [0] = 1; obj [1] = 2; 'Es funktioniert wie erwartet für den Nullindex. Es schlägt auf Index 1 fehl (oder irgendetwas anderes in dieser Angelegenheit). –

+0

@Rob: Welche Version von Moq laufen Sie? Ich habe tatsächlich zwei verschiedene Verhaltensweisen erlebt. Ich überprüfe die Version von Moq Ich lief in zwei verschiedenen Projekten und eins scheint zu arbeiten und das andere nicht. –

Antwort

1

Die Methode SetupSet nimmt einen einfachen Delegaten, nicht einen Ausdrucksbaum des Typs Expression<...> wie viele andere Moq-Methoden.

Aus diesem Grund kann Moq nicht sehen, dass Sie It.IsAny verwendet haben.Stattdessen ist It.IsAnygenannt (nicht was wir wollen) und Moq sieht nur seinen Rückgabewert, der zufällig default(int) oder ist.

1

Ab Moq 4.2.1502.0911 für .NET Framework 4.5 fand ich das folgende Verhalten, um wahr zu sein.

Das Problem, auf das Sie stoßen, ist speziell auf den Anruf It.IsAny<T> zurückzuführen. Wenn Sie It.IsAny<T> verwenden, wird der Rückruf nicht ausführen:

[Test] 
public void DoesNotExecuteCallback() 
{ 
    // Arrange 
    var mock = new Mock<IIndexable>(); 

    var called = false; 
    mock.SetupSet(m => m[It.IsAny<int>()] = It.IsAny<int>()).Callback<int,int>((x, y) => called = true); 

    var instance = mock.Object; 

    // Act 
    instance[1] = 2; 

    // Arrange 
    Assert.That(called, Is.False); 
} 

Aber wenn Sie es mit spezifischen Parametern aufrufen, ruft er den Rückruf:

[Test] 
public void DoesExecuteCallback() 
{ 
    // Arrange 
    var mock = new Mock<IIndexable>(); 

    var called = false; 
    mock.SetupSet(m => m[1] = 2).Callback<int,int>((x, y) => called = true); 

    var instance = mock.Object; 

    // Act 
    instance[1] = 2; 

    // Arrange 
    Assert.That(called, Is.True); 
} 

Um es zusammenzufassen, sollten Sie die Verwendung des It.IsAny vermeiden wenn versucht wird, Erwartungen für einen Indexer zu setzen. Im Allgemeinen sollten Sie die Verwendung von ihm werden vermieden, weil es schlampig Test

Es sind geeignete Anwendungsfälle für It.IsAny Schreiben fördern können, aber ohne die Besonderheiten zu wissen, neige ich dazu, das Unternehmen zu empfehlen.

+0

Ich sollte sagen, dass das, wofür ich Moq verwende, in keiner Weise als Komponententest betrachtet werden kann. – Rob

+1

Können Sie etwas konkreter sein, was Sie vorhaben? Während dieses eine sehr spezifische Szenario scheint nicht unterstützt zu werden, wenn Sie posten, was Sie wirklich versuchen, könnten wir in der Lage sein, eine Alternative zu finden. –

Verwandte Themen