Jak MOQ indeksowana właściwość

82

Próbuję sfałszować wywołanie zindeksowanej właściwości. Tj. Chciałbym zadać następujące pytania:

object result = myDictionaryCollection["SomeKeyValue"];

a także wartość ustawiającą

myDictionaryCollection["SomeKeyValue"] = myNewValue;

Robię to, ponieważ muszę kpić z funkcjonalności klasy, której używa moja aplikacja.

Czy ktoś wie, jak to zrobić z MOQ? Wypróbowałem różne warianty:

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

Ale to się nie kompiluje.

Czy to, co próbuję osiągnąć, jest możliwe dzięki MOQ, czy ktoś ma jakieś przykłady, jak mogę to zrobić?

Popiół
źródło
Czy nie byłoby łatwiej po prostu użyć obiektu pośredniego? Ustaw wymagane wartości i sprawdź potrzebne indeksy.
Søren Spelling Lund,

Odpowiedzi:

96

Nie jest jasne, co próbujesz zrobić, ponieważ nie pokazujesz deklaracji kpiny. Próbujesz kpić ze słownika?

MyContainer[(string s)] nie jest prawidłowy w C #.

To kompiluje:

var mock = new Mock<IDictionary>();
mock.SetupGet( p => p[It.IsAny<string>()]).Returns("foo");
Mike Scott
źródło
1
to też działa. z wyjątkiem nowej składni używa SetupSetzamiast ExpectGet. działa również dla seterów.
tmont
1
IDictionary pochodzi z System.Collections, a nie z System.Collections.Generic
upInCloud
20

Ash, jeśli chcesz mieć makietę sesji HTTP, to ten fragment kodu załatwia sprawę:

/// <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);
    }
}
wasker
źródło
Niezły - właśnie tego potrzebowałem +1
Ian Oxley
1
Jaka część tego kodu powoduje, że testowany kod korzysta z sesji próbnej? Czy TestSuiteBasebiblioteka czy twoja własna klasa?
StuperUser
1
To nie jest kpina, to podróbka. Tylko mówię.
Chris Peacock
17

Jak poprawnie zauważyłeś, istnieją różne metody SetupGeti SetupSetodpowiednio inicjalizujące metody pobierające i ustawiające. Chociaż SetupGetjest przeznaczony do użytku dla właściwości, a nie indeksatorów, i nie pozwoli na obsługę przekazanego klucza. Aby być precyzyjnym, dla indeksatorów SetupGeti Setuptak zadzwoni :

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);
    ...
  }
  ...
}

Aby odpowiedzieć na Twoje pytanie, oto przykładowy kod wykorzystujący podstawy Dictionarydo przechowywania wartości:

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);

Jak widać, musisz jawnie określić klucz, aby skonfigurować program ustawiający indeksator. Szczegóły opisano w innym pytaniu SO: Moq indeksowana właściwość i użyj wartości indeksu w funkcji return / callback

Vitaliy Ulantikov
źródło
1
To jest to, czego szukałem !! Żaden z innych przykładów nie zadziałał
Fiona - myaccessible.website
8

Nie jest to takie trudne, ale trochę zajęło znalezienie tego :)

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

Wygląda na to, że to, co próbowałem zrobić z MOQ, nie jest możliwe.

Zasadniczo próbowałem MOQ obiekt typu HTTPSession, w którym klucz elementu ustawianego na indeks można było określić tylko w czasie wykonywania. Dostęp do właściwości indeksowanej potrzebny do zwrócenia wartości, która została wcześniej ustawiona. Działa to w przypadku indeksów opartych na liczbach całkowitych, ale indeksy oparte na ciągach znaków nie działają.

Popiół
źródło