编程语言
首页 > 编程语言> > c#-使用Moles在单元测试中模拟会话变量

c#-使用Moles在单元测试中模拟会话变量

作者:互联网

我正在单元测试中检查会话变量的方法,例如

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

在我的测试中,由于Session为null,因此无法摆脱这种情况,它引发了null引用异常.

为了绕过这个,我尝试像下面这样嘲笑它,但是没有运气

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

我什至尝试方法提及here来模拟HttpContext,然后在下面做

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

但是再次没有运气.这次,尽管HttpContext.Current不是null而是HttpContext.Current.Session,因此引发了null ref异常.

我不知道该如何模拟/通过此测试[不使用任何外部DLL或更改主代码.抱歉,但负担不起].

感谢并感谢您的帮助.

解决方法:

2013年更新:

现在的坏消息是Moles框架是Microsoft Research(MSR)项目,是will not be supported in Visual Studio 2012.好消息是,微软现在已将MSR项目集成到主线框架中,名称为Microsoft Fakes.

我找到了一篇文章,使用Fakes框架而不是Moles框架解决了您遇到的问题:

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

这是我以前的答案的更新版本,使用Fakes框架而不是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;
    }
};

您甚至可以使它看起来更像我以前发布的Moles版本,尽管我还没有尝试过.我只是根据我的答案修改文章的代码:)

2013年之前编辑:

您说过要避免更改被测代码.虽然我认为应该进行更改,但是像这样直接访问会话状态不是一个好主意,但我可以理解您来自何处(我曾经在测试中……).

我找到了this thread describing how someone moled both HttpContext and HttpSessionState to get around this problem.

他们的代码最终看起来像这样:

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

编辑之前:

我通常通过使用可以实例化和模拟化的抽象类或接口封装全局状态来解决此类问题.然后,我没有直接访问全局状态,而是将抽象类或接口的实例注入使用它的代码中.

这使我可以模拟全局行为,并使其不受测试或依赖于无关行为.

这是做到这一点的一种方法(我会稍微考虑一下因素):

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
    }
}

这将需要更改您的被测代码,但是这种类型的更改对于代码的可测试性和可移植性都有利.

标签:unit-testing,session-variables,moles,asp-net,c
来源: https://codeday.me/bug/20191101/1987263.html