【问题标题】:ASP.NET MVC FakeItEasy - Mocked session does not return correct value in unit testASP.NET MVC FakeItEasy - 模拟会话在单元测试中不返回正确的值
【发布时间】:2014-05-29 02:19:55
【问题描述】:

我已经使用 FakeItEasy 模拟了 MVC 控制器中的会话对象:

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

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

如果您在控制器操作中访问会话对象,它将返回正确的值:

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

    ...
}

这个问题稍后会出现在控制器中,其中会话是通过这样的设置器使用相同的键设置的:

Session["Key"] = "SomeOtherValue";

然后当使用密钥时,它返回错误值

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

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

【问题讨论】:

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


    【解决方案1】:

    Tim Long 拥有此权利。什么是“正确的价值”? 但是,返回密钥是一种奇怪的行为。

    我想我们在这里有一个功能请求的素材。 (我做了一个: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");
    }
    

    【讨论】:

    • 感谢 Blair 的回复,我试过你的解决方案,但我得到一个:“System.Web.dll 中发生“System.NotImplementedException”类型的异常,但未在用户代码附加信息:方法或操作未实现。" 执行 session["key2"] = "value2" 时发生这种情况
    • 啊,废话。这就是我在编写解决方案时使用自己的 Session 任务所得到的。我没有意识到HttpSessionStateBase.Item 总是抛出 NotImplementedException (msdn.microsoft.com/en-us/library/cc647353(v=vs.110).aspx)。对于那个很抱歉。在这种情况下,我想替代方案不是回退到基本实现,而是实现您自己的后备存储 - 只需在测试类上抛出一个 Dictionary 并设置 setter/getter 并从中获取。我无法运行 Visual Studio 此时,但如果没有其他人可以,稍后会修改答案。
    • 当然,一旦后备存储正常工作,A.CallTo(() =&gt; session["key1"]).Returns("value1") 可能就不再需要了——也许session["key1"] = "value1" 就足够了。 YMMV。
    【解决方案2】:

    一个突出的问题可能是:在这种情况下正确的价值是什么?您似乎对是否希望此索引器表现得像一个模拟或真正的索引器有冲突。您首先使用要返回的固定值配置模拟,然后即使您没有模拟它,您也可以写入索引器。那么 FakeItEasy 应该如何处理书面价值呢?它现在应该返回您告诉它返回的模拟值,还是应该以某种方式知道您现在的意思是新值?它是怎么知道的?

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

    您是否考虑过使用不同的设置,例如ReturnsNextFromSequence()ReturnsLazily()

    【讨论】:

    • 你说得对,蒂姆,很抱歉不清楚。在现实世界中,会话设置为与模拟对象相同的值。所以我期待 Session["Key"] 返回 "SomeValue" :) 奇怪的是它返回 "Key" 作为我认为很疯狂的值。我可以尝试删除模拟值,看看会发生什么..
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-29
    • 1970-01-01
    相关资源
    最近更新 更多