ASP.NET MVC FakeItEasy - Mocked会话在单元测试中没有返回正确的值

时间:2014-03-19 15:20:30

标签: c# asp.net-mvc unit-testing session fakeiteasy

我使用FakeItEasy模拟了MVC控制器中的Session对象:

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

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

如果您在控制器操作中访问session-object,它将返回正确的值:

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

    ...
}

稍后在控制器中出现问题,通过这样的setter使用相同的密钥设置会话:

Session["Key"] = "SomeOtherValue";

然后当使用该键时,它返回错误的值

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

模拟会话不再返回我的模拟值,它也不返回新值,而是返回键(WTF ?!)。我究竟做错了什么?使用setter时,模拟对象实际发生了什么?

2 个答案:

答案 0 :(得分:3)

Tim Long有权利。什么是&#34;正确的价值&#34;? 然而,返回密钥是一种奇怪的行为。

我认为我们这里有一个功能请求的饲料。 (我已经做了一个:issue 277。) 我认为使用getter和setter的未配置索引属性存储值并稍后返回它是合理的。

更新:问题277已在FakeItEasy 1.21.0中修复。从NuGet获取它(或更新的版本)。

与此同时,您可以解决类似这个我在调用原始方法时指出问题后所做的新示例

[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");
}

答案 1 :(得分:2)

一个突出的问题可能是:在这种情况下什么是正确的价值?对于您是否希望此索引器的行为类似于模拟或真正的索引器,您似乎存在冲突。首先配置一个带有固定值的mock来返回,然后你写入索引器,即使你没有嘲笑它。那么FakeItEasy应该如何处理书面价值呢?它现在应该返回你告诉它返回的模拟值,还是应该知道你现在意味着新值?怎么知道?

你既不会得到旧值也不会得到新值这一事实有点奇怪,但看看HAL 9000在给出相互矛盾的指令时发生了什么!这可能表明您需要采用不同的方法。

您是否考虑过使用其他设置,例如ReturnsNextFromSequence()ReturnsLazily()