سؤال

I've mocked the Session-object in the MVC Controller using FakeItEasy by doing:

var session = A.Fake<HttpSessionStateBase>();
A.CallTo(() => session["SomeKey"]).Returns("SomeValue");

Controller.ControllerContext = new ControllerContext(mockHttpContext, new RouteData(), Controller);

And if you in the controller action access the session-object it will return the correct value:

public ActionResult Index()
{
    var value = Session["Key"]; // value = "SomeValue" like it is supposed to

    ...
}

The problem occurs later on in the controller where the session is set using the same key via a setter like this:

Session["Key"] = "SomeOtherValue";

And then when the key is used it returns the wrong value:

var value = Session["Key"]; // value = "Key" 

The mocked session does not return my mocked value anymore and it does not return the new value either, but instead it returns the key (WTF?!). What am I doing wrong? What actually happens with the mocked object when the setter is used?

هل كانت مفيدة؟

المحلول

Tim Long has the right of it. What is the "right value"? However, returning the key is weird behaviour.

I think we have fodder for a feature request in here. (And I've made one: issue 277.) I think it would be reasonable for unconfigured indexed properties with getters and setters to store values and return them later.

Update: issue 277 has been fixed in FakeItEasy 1.21.0. Get it (or a newer version) from NuGet.

In the meantime, you can workaround with something like this new example I made after you pointed out the problem with calling the original methods:

[Test]
public void TestItemProperty()
{
    var mySession = new Dictionary<string, object>();
    var session = A.Fake<HttpSessionStateBase>();
    A.CallTo(session)
        .Where(call => call.Method.Name == "set_Item")
        .Invokes((string key, object value) => mySession[key] = value);

    A.CallTo(() => session[A<string>._])
        .ReturnsLazily((string key) => mySession[key]);
    A.CallTo(() => session["key1"]).Returns("value1");

    A.CallTo(() => session["key1"]).Returns("value1");
    Assert.That(session["key1"], Is.EqualTo("value1"));

    session["key2"] = "value2";
    Assert.That(session["key2"], Is.EqualTo("value2"));

    Assert.That(session["key1"], Is.EqualTo("value1"), "second go");
}

نصائح أخرى

A salient question might be: what is the right value under those circumstances? It seems like you are conflicted about whether you want this indexer to behave like a mock, or a real indexer. You start by configuring the mock with a fixed value to return, then you write to the indexer even though you haven't mocked that. So what's FakeItEasy supposed to do with the written value? Should it now return the mock value that you've told it to return, or should it somehow know that you mean the new value now? How does it know?

The fact that you get neither the old nor the new value is a bit odd, but look what happened to the HAL 9000 when it was given conflicting instructions! This is probably a sign that you need a different approach.

Have you considered using a different setup, such as ReturnsNextFromSequence() or ReturnsLazily()?

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top