使用痣在单元测试嘲讽会话变量 [英] mocking session variable in unit test using Moles

查看:230
本文介绍了使用痣在单元测试嘲讽会话变量的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

方法我是一个会话变量的单元测试检查像

Method I am unit testing checks for a session variable like

if(Session["somevar"] != null)
{
   // rest of the code
}

在我的测试中,不能因为会话来摆脱这种为空,它的投掷空参鉴例外。

In my test, not able to get rid of this since Session is null, it's throwing null referrence exception.

要绕过这一点,我试图嘲弄它像下面,但没有运气

To bypass this, I have tried mocking it like below but no luck

System.Web.Moles.MHttpContext.AllInstances.SessionGet = (HttpContext cntx) =>
{ return (HttpSessionState)cntx.Session["somevar"]; }

我甚至尝试的方法提这里模拟的HttpContext,然后做以下

I even tried method mention here to simulate HttpContext and then doing below

HttpContext.Current = new HttpContext(workerRequest);
HttpContext.Current.Session["somevar"] = value;

但同样没有运气。这一次,虽然 HttpContext.Current 不为空,但 HttpContext.Current.Session ,因此抛出空REF异常。

But again no luck. This time, though the HttpContext.Current is not null but HttpContext.Current.Session and hence throws null ref exception.

任何想法,我怎么能嘲笑这种/在我的测试此通过[无需使用任何外部DLL或主code修改。很抱歉,但不能这样做。

Any idea how can I mock this/by pass this in my test [Without using any external DLL or main code change. Sorry, but can't afford to do so].

感谢和AP preaciate很大的帮助。

Thanks and appreaciate lot your help.

推荐答案

更​​新2013:

坏消息,现在是,鼹鼠框架是微软研究院(MSR)项目,的不会在Visual Studio 2012 的支持。好消息是,微软现在已经集成了MSR项目进入主线框架的微软正版正货

The bad news now is that the Moles framework was a Microsoft Research (MSR) project, and will not be supported in Visual Studio 2012. The great news is that Microsoft has now integrated the MSR project into the mainline framework as Microsoft Fakes.

我发现,解决你有问题的文章,用假货框架,而不是鼹鼠框架:

I found an article that solves the problem you had, using the Fakes framework instead of the Moles framework:

http://blog.christopheargento.net/2013/02/02/testing-untestable-$c$c-thanks-to-ms-fakes/

下面是一个使用假货的框架,而不是我的痣previous答案的更新版本。

Here's an updated version of my previous answer that uses the Fakes framework instead of Moles.

using System.Web.Fakes;

// ...

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

ShimHttpContext.CurrentGet = () => new ShimHttpContext();
ShimHttpContext.AllInstances.SessionGet = (o) => new ShimHttpSessionState
{
    ItemGetString = (key) =>
    {
        object result = null;
        sessionState.TryGetValue(key, out result);
        return result;
    }
};

您甚至可能能够使它看起来更像鼹鼠版本之前我贴出来,虽然我还没有试过了没有。我只是适应文章的code到我的回答:)

You might even be able to make it look more like the Moles version I posted before, though I haven't tried that out yet. I'm just adapting the article's code to my answer :)

在2013编辑:

你说你想避免被测改变code。虽然我认为它的的改变,这样的直接访问会话状态是一个坏主意,我能理解你的出发点来(我是在一次试验...)。

You said you want to avoid changing the code under test. While I think it should be changed, as directly accessing session state like that is a bad idea, I can understand where you're coming from (I was in test once...).

我发现这个线程描述如何有人moled既的HttpContext HttpSessionState 来解决这个问题

I found this thread describing how someone moled both HttpContext and HttpSessionState to get around this problem.

他们的code弄成这样看:

Their code ended up looking like this:

MHttpContext.CurrentGet = () => new MHttpContext
{
    SessionGet = () => new MHttpSessionState
    {
        ItemGetString = (key) =>
        {
            if (key == "some")
                return "someString"/* or any other object*/;
            else return null;
        }
    }
};

我想走得更远,实施 ItemGetString 借助字典:

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

MHttpContext.CurrentGet = // ...
{
    // ...
    ItemGetString = (key) =>
    {
        object result = null;
        sessionState.TryGetValue(key, out result);
        return result;
    }


修改前:

我通常用一个抽象类或者接口可以被实例化,嘲笑了封装的全局状态解决这样的问题。然后,而不是直接访问全局状态,我注入我的抽象类或接口的实例,为使用它的code。

I usually solve problems like this by encapsulating global state with an abstract class or interface that can be instanced and mocked out. Then instead of directly accessing the global state, I inject an instance of my abstract class or interface into the code that uses it.

这让我模拟出全球行为,使得它如此我的测试不依赖于或行使无关的行为。

This lets me mock out the global behavior, and makes it so my tests don't depend on or exercise that unrelated behavior.

下面是做到这一点的一种方式(我与保理玩了一下寿):

Here's one way to do that (I'd play with the factoring a bit tho):

public interface ISessionContext
{
    object this[string propertyName] { get; set; }
}

public class ServerContext : ISessionContext
{
    public object this[string propertyName]
    {
        get { return HttpContext.Current.Session[propertyName]; }
        set { HttpContext.Current.Session[propertyName] = value; }
    }
}

public class SomeClassThatUsesSessionState
{
    private readonly ISessionContext sessionContext;

    public SomeClassThatUsesSessionState(ISessionContext sessionContext)
    {
        this.sessionContext = sessionContext;
    }

    public void SomeMethodThatUsesSessionState()
    {
        string somevar = (string)sessionContext["somevar"];
        // todo: do something with somevar
    }
}

这将要求改变您的code盘下测试,但它的变化的类型都为可测试性,为code的便携性还是不错的。

This would require changes to your code-under-test, but it is the type of change that is good both for testability and for portability of the code.

这篇关于使用痣在单元测试嘲讽会话变量的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆