So MOQEN Sie eine indizierte Eigenschaft

81

Ich versuche, einen Aufruf einer indizierten Eigenschaft zu verspotten. Dh ich möchte folgendes moq:

object result = myDictionaryCollection["SomeKeyValue"];

und auch den Setterwert

myDictionaryCollection["SomeKeyValue"] = myNewValue;

Ich mache das, weil ich die Funktionalität einer Klasse verspotten muss, die meine App verwendet.

Weiß jemand, wie man das mit MOQ macht? Ich habe folgende Variationen ausprobiert:

Dictionary<string, object> MyContainer = new Dictionary<string, object>();
mock.ExpectGet<object>( p => p[It.IsAny<string>()]).Returns(MyContainer[(string s)]);

Das lässt sich aber nicht kompilieren.

Ist das, was ich mit MOQ erreichen möchte, möglich? Hat jemand Beispiele dafür, wie ich das tun kann?

Asche
quelle
Wäre es nicht einfacher, nur ein Stub-Objekt zu verwenden? Stellen Sie die erforderlichen Werte ein und überprüfen Sie die benötigten Indizes.
Søren Spelling Lund

Antworten:

95

Es ist nicht klar, was Sie versuchen, weil Sie die Erklärung des Scheines nicht zeigen. Versuchen Sie, ein Wörterbuch zu verspotten?

MyContainer[(string s)] ist nicht gültig C #.

Dies kompiliert:

var mock = new Mock<IDictionary>();
mock.SetupGet( p => p[It.IsAny<string>()]).Returns("foo");
Mike Scott
quelle
1
das funktioniert auch. außer die neue Syntax verwendet SetupSetanstelle von ExpectGet. funktioniert auch für Setter.
Montag,
1
Das IDictionary ist von System.Collections und nicht von System.Collections.Generic
upInCloud
20

Ash, wenn Sie einen HTTP-Sitzungs-Mock haben möchten, dann erledigt dieser Code den Job:

/// <summary>
/// HTTP session mockup.
/// </summary>
internal sealed class HttpSessionMock : HttpSessionStateBase
{
    private readonly Dictionary<string, object> objects = new Dictionary<string, object>();

    public override object this[string name]
    {
        get { return (objects.ContainsKey(name)) ? objects[name] : null; }
        set { objects[name] = value; }
    }
}

/// <summary>
/// Base class for all controller tests.
/// </summary>
public class ControllerTestSuiteBase : TestSuiteBase
{
    private readonly HttpSessionMock sessionMock = new HttpSessionMock();

    protected readonly Mock<HttpContextBase> Context = new Mock<HttpContextBase>();
    protected readonly Mock<HttpSessionStateBase> Session = new Mock<HttpSessionStateBase>();

    public ControllerTestSuiteBase()
        : base()
    {
        Context.Expect(ctx => ctx.Session).Returns(sessionMock);
    }
}
Waschmaschine
quelle
Schön - das war genau das, was ich brauchte +1
Ian Oxley
1
Welcher Teil dieses Codes veranlasst den zu testenden Code, die Mock-Sitzung zu verwenden? Ist TestSuiteBaseeine Bibliothek oder Ihre eigene Klasse?
StuperUser
1
Das ist kein Schein, es ist eine Fälschung. Nur sagen.
Chris Peacock
17

Wie Sie richtig entdeckt, gibt es verschiedene Methoden SetupGetund SetupSetjeweils Getter und Setter zu initialisieren. Obwohl SetupGetfür Eigenschaften und nicht für Indexer vorgesehen ist und Sie keine an ihn übergebenen Schlüssel verarbeiten können. Um genau zu sein, werden Indexer trotzdem SetupGetanrufen Setup:

internal static MethodCallReturn<T, TProperty> SetupGet<T, TProperty>(Mock<T> mock, Expression<Func<T, TProperty>> expression, Condition condition) where T : class
{
  return PexProtector.Invoke<MethodCallReturn<T, TProperty>>((Func<MethodCallReturn<T, TProperty>>) (() =>
  {
    if (ExpressionExtensions.IsPropertyIndexer((LambdaExpression) expression))
      return Mock.Setup<T, TProperty>(mock, expression, condition);
    ...
  }
  ...
}

Um Ihre Frage zu beantworten, finden Sie hier ein Codebeispiel mit dem zugrunde liegenden DictionaryWert zum Speichern von Werten:

var dictionary = new Dictionary<string, object>();

var applicationSettingsBaseMock = new Mock<SettingsBase>();
applicationSettingsBaseMock
    .Setup(sb => sb[It.IsAny<string>()])
    .Returns((string key) => dictionary[key]);
applicationSettingsBaseMock
    .SetupSet(sb => sb["Expected Key"] = It.IsAny<object>())
    .Callback((string key, object value) => dictionary[key] = value);

Wie Sie sehen können, müssen Sie den Schlüssel explizit angeben, um den Indexer-Setter einzurichten. Details werden in einer anderen SO-Frage beschrieben: Moq eine indizierte Eigenschaft und verwenden Sie den Indexwert in der Rückgabe / Rückruf

Vitaliy Ulantikov
quelle
1
Das habe ich gesucht !! Keines der anderen Beispiele hat funktioniert
Fiona - myaccessible.website
8

Es ist nicht so schwierig, aber es hat ein bisschen gedauert, es zu finden :)

var request = new Moq.Mock<HttpRequestBase>();
request.SetupGet(r => r["foo"]).Returns("bar");
JustEngland
quelle
-4

Es scheint, dass das, was ich mit MOQ versucht habe, nicht möglich ist.

Im Wesentlichen habe ich versucht, ein Objekt vom Typ HTTPSession zu MOQ, bei dem der Schlüssel des Elements, das auf den Index gesetzt wird, nur zur Laufzeit ermittelt werden konnte. Zugriff auf die indizierte Eigenschaft, die erforderlich ist, um den zuvor festgelegten Wert zurückzugeben. Dies funktioniert für ganzzahlige Indizes, aber stringbasierte Indizes funktionieren nicht.

Asche
quelle