Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/entity-framework/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何在ShoppingCart控制器/模型中模拟HttpContext_C#_Entity Framework_Unit Testing_Asp.net Mvc 4 - Fatal编程技术网

C# 如何在ShoppingCart控制器/模型中模拟HttpContext

C# 如何在ShoppingCart控制器/模型中模拟HttpContext,c#,entity-framework,unit-testing,asp.net-mvc-4,C#,Entity Framework,Unit Testing,Asp.net Mvc 4,在基于实体框架4.0的MVC4应用程序中,我们使用Moq模拟DbContext和单元测试是逻辑。我们的一种方法很难测试,因为它使用了HttpContext或HttpContextBase。一个示例方法如下所示: public static ShoppingCart GetCart(HttpContextBase context) { var cart = new ShoppingCart(); cart.ShoppingCartId = cart.GetC

在基于实体框架4.0的MVC4应用程序中,我们使用Moq模拟
DbContext
和单元测试是逻辑。我们的一种方法很难测试,因为它使用了
HttpContext
HttpContextBase
。一个示例方法如下所示:

public static ShoppingCart GetCart(HttpContextBase context)
    {
        var cart = new ShoppingCart();
        cart.ShoppingCartId = cart.GetCartId(context);
        return cart;
    }
        var mockData = new Mock<FakeContext>();
        mockData.Setup(m => m.Orders).Returns(memoryOrderItems);
        mockData.Setup(m => m.Carts).Returns(memoryCartItems);

        Mock<HttpContextBase> mockHttpContext = new Mock<HttpContextBase>();
        Mock<HttpRequestBase> mockHttpRequest = new Mock<HttpRequestBase>();

        mockHttpRequest.Setup(x => x.CartSessionKey).Returns(1);
        mockHttpContext.Setup(x => x.Request).Returns(mockHttpRequest.Object);
HttpContextBase
收集的唯一属性是
[CartSessionKey]
,如下所示:

public string GetCartId(HttpContextBase context)
{
    if (context.Session[CartSessionKey] == null)
    {
        if (!string.IsNullOrWhiteSpace(context.User.Identity.Name))
        {
            context.Session[CartSessionKey] =
                context.User.Identity.Name;
        }
        else
        {
            // Generate a new random GUID using System.Guid class
            Guid tempCartId = Guid.NewGuid();
            // Send tempCartId back to client as a cookie
            context.Session[CartSessionKey] = tempCartId.ToString();
        }
    }
    return context.Session[CartSessionKey].ToString();
}
我们听说过一些恐怖故事,比如说
HttpContext
是一个非常复杂的类,如果你把它打印出来,你就有足够的纸绕地球转八圈

然而,我们想嘲笑它。问题是怎么做。我们要模拟的属性是
[CartSessionKey]
,以及来自上下文的属性
contest.User.Identity.Name

我们怀疑我们需要使用这样的东西:

public static ShoppingCart GetCart(HttpContextBase context)
    {
        var cart = new ShoppingCart();
        cart.ShoppingCartId = cart.GetCartId(context);
        return cart;
    }
        var mockData = new Mock<FakeContext>();
        mockData.Setup(m => m.Orders).Returns(memoryOrderItems);
        mockData.Setup(m => m.Carts).Returns(memoryCartItems);

        Mock<HttpContextBase> mockHttpContext = new Mock<HttpContextBase>();
        Mock<HttpRequestBase> mockHttpRequest = new Mock<HttpRequestBase>();

        mockHttpRequest.Setup(x => x.CartSessionKey).Returns(1);
        mockHttpContext.Setup(x => x.Request).Returns(mockHttpRequest.Object);
然后这个:

        // Create mock units of work
        var mockData = new Mock<FakeContext>();
        mockData.Setup(m => m.Orders).Returns(memoryOrderItems);
        mockData.Setup(m => m.Carts).Returns(memoryCartItems);
        mockData.Setup(m => m.Users).Returns(memoryUserItems);

        var principalMock = new Mock<IPrincipal>();
        var identityMock = new Mock<IIdentity>();
        var userMock = 
        identityMock.Setup(x => x.Name).Returns("Test!");
        identityMock.Setup(x => x.IsAuthenticated).Returns(true); // optional ;)
        mockData.Setup(x => x.Identity).Returns(identityMock.Object);
        var httpReqBase = new Mock<HttpRequestBase>(); // this is useful if you want to test Ajax request checks or cookies in the controller.
        var httpContextBase = new Mock<HttpContextBase>();

        httpContextBase.Setup(x => x.User).Returns(principalMock.Object);
        httpContextBase.Setup(x => x.Session[It.IsAny<string>()]).Returns(1); //Here is the session indexer. You can swap 'any' string for specific string.
        httpContextBase.Setup(x => x.Request).Returns(httpReqBase.Object);
可以看到,
var cart=ShoppingCart.GetCart(this.HttpContext)
使用
this.HttpContext
。在测试中,我只做了
controller.Complete(1)
。我无法将新的
HttpContext
传递给我猜的控制器

/编辑3

将下面的代码用于模拟时,我得到以下消息:

Test Name:  TestCheckoutCompleteShouldWithEmptyCart
Test FullName:  Controllers.CheckoutControllerTest.TestCheckoutCompleteShouldWithEmptyCart
Test Source:    Controllers\CheckoutControllerTest.cs : line 141
Test Outcome:   Failed
Test Duration:  0:00:00.0158591

Result Message: 
Test method Controllers.CheckoutControllerTest.TestCheckoutCompleteShouldWithEmptyCart threw exception: 
System.NullReferenceException: Object reference not set to an instance of an object.
Result StackTrace:  
at Models\ShoppingCart.cs:line 170
   at \Models\ShoppingCart.cs:line 20
   at \Controllers\CheckoutController.cs:line 48
   at Controllers\CheckoutControllerTest.cs:line 143

好了,开始了。以下内容在MVC5和AD中工作,我不确定它是否完全向后兼容,您必须检查

var principalMock = new Mock<IPrincipal>();
var identityMock = new Mock<IIdentity>();
identityMock.Setup(x => x.Name).Returns("Test!");
identityMock.Setup(x => x.IsAuthenticated).Returns(true); // optional ;)
userMock.Setup(x => x.Identity).Returns(identityMock.Object);
var httpReqBase = new Mock<HttpRequestBase>(); // this is useful if you want to test Ajax request checks or cookies in the controller.
var httpContextBase = new Mock<HttpContextBase>();

httpContextBase.Setup(x => x.User).Returns(principalMock.Object);
httpContextBase.Setup(x => x.Session[It.IsAny<string>()]).Returns(1); //Here is the session indexer. You can swap 'any' string for specific string.
httpContextBase.Setup(x => x.Request).Returns(httpReqBase.Object);
var principalMock=new Mock();
var identityMock=new Mock();
Setup(x=>x.Name)。返回(“Test!”);
identityMock.Setup(x=>x.IsAuthenticated)。返回(true);//可选;)
userMock.Setup(x=>x.Identity).Returns(identityMock.Object);
var httpReqBase=new Mock();//如果您想在控制器中测试Ajax请求检查或cookie,这非常有用。
var httpContextBase=new Mock();
Setup(x=>x.User).Returns(principalMock.Object);
httpContextBase.Setup(x=>x.Session[It.IsAny()])。返回(1)//这是会话索引器。您可以将“任意”字符串交换为特定字符串。
Setup(x=>x.Request).Returns(httpReqBase.Object);

这将帮助您使用Moq编写正确的单元测试

[TestClass]
public class SutTest
{
    [TestMethod]
    public void GetCartId_WhenUserNameIsNotNull_SessionContainsUserName()
    {
        var httpContextStub = new Mock<HttpContextBase>();
        var httpSessionStub = new Mock<ISessionSettings>();
        httpSessionStub.Setup(x => x.Get<string>(It.IsAny<string>())).Returns(() => null);

        httpSessionStub.SetupSequence(x => x.Get<string>(It.IsAny<string>()))
            .Returns(null)
            .Returns("FakeName");

        var httpUserStub = new Mock<IPrincipal>();
        var httpIdenttyStub = new Mock<IIdentity>();
        httpUserStub.SetupGet(x => x.Identity).Returns(httpIdenttyStub.Object);
        httpIdenttyStub.SetupGet(x => x.Name).Returns("FakeName");

        httpContextStub.Setup(x => x.User).Returns(httpUserStub.Object);
        var sut = new Sut(httpSessionStub.Object);

        var result = sut.GetCartId(httpContextStub.Object);

        Assert.AreEqual("FakeName",result );
    }
}
[TestClass]
公共类测试
{
[测试方法]
public void GetCartId_WhenUserNameIsNotNull_SessionContainsUserName()
{
var httpContextStub=new Mock();
var httpSessionStub=new Mock();
httpSessionStub.Setup(x=>x.Get(It.IsAny())。返回(()=>null);
httpSessionStub.SetupSequence(x=>x.Get(It.IsAny()))
.Returns(null)
.返回(“FakeName”);
var httpUserStub=new Mock();
var httpidentistub=new Mock();
SetupGet(x=>x.Identity).Returns(httpidentitystub.Object);
httpidentistub.SetupGet(x=>x.Name).Returns(“FakeName”);
设置(x=>x.User).Returns(httpUserStub.Object);
var sut=新sut(httpSessionStub.Object);
var result=sut.GetCartId(httpContextStub.Object);
Assert.AreEqual(“FakeName”,结果);
}
}
检查SetupSequence方法,它可以让您找到对同一存根调用返回的不同值的控制。 将会话与HttpContext分离也很重要,因为您总是会遇到问题

public class SessionSettings : ISessionSettings
{
    private readonly HttpSessionStateBase _session;
    public SessionSettings(HttpSessionStateBase session)
    {
        _session = session;
    }

    public T Get<T>(string key)
    {
        return (T)_session[key];
    }

    public void Set<T>(string key, T value)
    {
        _session[key] = value;
    }
}

public interface ISessionSettings
{
    T Get<T>(string key);
    void Set<T>(string key, T value);
}

public class Sut
{
    private ISessionSettings _sessionSettings;
    public Sut(ISessionSettings sessionSettings)
    {
        _sessionSettings = sessionSettings;
    }
    public string GetCartId(HttpContextBase context)
    {
        if (_sessionSettings.Get<string>(CartSessionKey) == null)
        {
            if (!string.IsNullOrWhiteSpace(context.User.Identity.Name))
            {
                _sessionSettings.Set<string>(CartSessionKey, context.User.Identity.Name);
            }
            else
            {
                // Generate a new random GUID using System.Guid class
                Guid tempCartId = Guid.NewGuid();
                // Send tempCartId back to client as a cookie
                _sessionSettings.Set<string>(CartSessionKey, tempCartId.ToString());
            }
        }
        return _sessionSettings.Get<string>(CartSessionKey);
    }

    private string CartSessionKey = "key";
}
公共类会话设置:ISessionSettings
{
私有只读HttpSessionStateBase\u会话;
公共会话设置(HttpSessionStateBase会话)
{
_会话=会话;
}
公共T获取(字符串键)
{
返回(T)_会话[键];
}
公共无效集(字符串键,T值)
{
_会话[键]=值;
}
}
公共接口设置
{
T Get(字符串键);
无效集(字符串键,T值);
}
公共类Sut
{
私人ISessionSettings(会话设置);
公共Sut(ISessionSettings会话设置)
{
_会话设置=会话设置;
}
公共字符串GetCartId(HttpContextBase上下文)
{
if(_sessionSettings.Get(CartSessionKey)==null)
{
if(!string.IsNullOrWhiteSpace(context.User.Identity.Name))
{
_Set(CartSessionKey,context.User.Identity.Name);
}
其他的
{
//使用System.GUID类生成新的随机GUID
Guid tempCartId=Guid.NewGuid();
//将tempCartId作为cookie发送回客户端
_Set(CartSessionKey,tempCartId.ToString());
}
}
return\u sessionSettings.Get(CartSessionKey);
}
私有字符串CartSessionKey=“key”;
}

这样,代码更容易阅读和理解。

您正在测试公共字符串GetCartId(HttpContextBase context)方法吗?你的目标是什么?GetCart还是GetCartId?嗨@Spock,什么是MUT
GetCartId
是主要关注点,因为
GetCart
依赖于此。很抱歉,这是正在测试的方法。你想要达到的目标很容易。看我的答案还有其他几种方法。很高兴为您提供帮助我认为测试公共GetCartId比测试GetCart更有价值,因为它几乎没有什么行为。@Spock关键是这个方法被很多其他方法(我想测试)使用,它们在这个方法上出现了问题。谢谢。我已经为一个新问题编辑了这个问题,这个问题是由
userMock
对象提出的。你能解释一下如何使
x.Identity
部分工作吗?@user2609980你的
FakeContext
看起来怎么样?它是否使用
IIdentity
?它由每个
模型的
公共虚拟IDbSet
组成(例如,
公共虚拟IDbSet产品{get;set;}
和两个空方法,如
公共int SaveChanges(){return 1;}
公共void Dispose(){抛出新的NotImplementedException();}