Asp.net mvc 用Moq模拟HttpContextBase
我有一个单元测试装置,我试图在ASP.NET MVC控制器上测试ControllerAction,该控制器用于web应用程序上的成员资格函数。我试图模拟测试的HttpContext。测试中的ControllerAction实际上在HttpContext上设置属性,例如会话值、响应.Cookies值等。这不是全部代码,但下面是我尝试运行的测试的粗略示例:Asp.net mvc 用Moq模拟HttpContextBase,asp.net-mvc,moq,Asp.net Mvc,Moq,我有一个单元测试装置,我试图在ASP.NET MVC控制器上测试ControllerAction,该控制器用于web应用程序上的成员资格函数。我试图模拟测试的HttpContext。测试中的ControllerAction实际上在HttpContext上设置属性,例如会话值、响应.Cookies值等。这不是全部代码,但下面是我尝试运行的测试的粗略示例: [Test] public void ValidRegistrationDataSuccessfullyCreatesAndRegistersU
[Test]
public void ValidRegistrationDataSuccessfullyCreatesAndRegistersUser()
{
var context = new Mock<HttpContextBase>() {DefaultValue = DefaultValue.Mock};
context.SetupAllProperties();
var provider = new Mock<MembershipProvider>(new object[] {context.Object});
var controller = new AccountController(context.Object, provider.Object);
// This just sets up a local FormCollection object with valid user data
// in it to use to attempt the registration
InitializeValidFormData();
ActionResult result = controller.Register(_registrationData);
Assert.IsInstanceOfType(typeof(ViewResult), result);
// Here is where I'd like to attempt to do Assertions against properties
// of the HttpContext, like ensuring that a Session object called "User"
// exists, and new auth cookie exists on the Response.Cookies collection.
// So far I've been unable to successfully check the values of those properties.
// I've been unsuccessful in getting those properties setup correctly on my
// mock object so that my ControllerAction can actually *set* their values,
// and that I can make assertions on them afterwards. The above code actually
// generates a StackOverflowException (which I've reported) on the
// context.SetupAllProperties() call. What am I doing wrong, or what do I need
// to do to be able to set and assert on those context properties?
}
[测试]
public void validRegistrationDataSuccessfullyCreateandRegistersUser()
{
var context=new Mock(){DefaultValue=DefaultValue.Mock};
SetupAllProperties();
var provider=newmock(新对象[]{context.object});
var控制器=新的AccountController(context.Object、provider.Object);
//这只是使用有效的用户数据设置一个本地FormCollection对象
//在它中,用于尝试注册
初始化EvalidFormData();
ActionResult=controller.Register(注册数据);
IsInstanceOfType(typeof(ViewResult),result);
//这里是我想要尝试对属性进行断言的地方
//HttpContext,比如确保一个名为“User”的会话对象
//存在,并且Response.Cookies集合上存在新的身份验证cookie。
//到目前为止,我无法成功地检查这些属性的值。
//我无法在我的计算机上正确设置这些属性
//模拟对象,以便我的ControllerAction可以实际*设置*它们的值,
//之后我可以对它们进行断言。上面的代码实际上
//在服务器上生成StackOverflowException(我已经报告过)
//SetupAllProperties()调用。我做错了什么,或者我需要什么
//如何设置和断言这些上下文属性?
}
我不确定我做错了什么,但如果有人能给我指出正确的方向,告诉我如何设置这个模拟的HttpContextBase对象,这样我的控制器就可以在其属性上设置值,我就可以对这些属性进行断言,以确保我的ControllerAction正在做我需要它做的事情,我会很高兴
我是不是走错了路?我知道MVC控制器有一个ControllerContext,我可以用它来设置会话等的值,但我不知道如何不注入它就可以模拟类似的东西。有什么方法可以替代吗?(我还需要能够将上下文传递给我的会员资格提供商)这是更好的方法吗
谢谢。
公共静态HttpContextBase FakeHttpContext()
{
var context=newmock();
var request=newmock();
var response=newmock();
var session=newmock();
var server=newmock();
var user=new Mock();
var identity=newmock();
Expect(req=>req.ApplicationPath)。返回(“~/”;
Expect(req=>req.AppRelativeCurrentExecutionFilePath)。返回(“~/”;
Expect(req=>req.PathInfo).Returns(string.Empty);
Expect(res=>res.ApplyAppPathModifier(It.IsAny()))
.返回((字符串virtualPath)=>virtualPath);
Expect(usr=>usr.Identity).Returns(Identity.Object);
identity.ExpectGet(ident=>ident.IsAuthenticated).返回(true);
Expect(ctx=>ctx.Request).Returns(Request.Object);
Expect(ctx=>ctx.Response).Returns(Response.Object);
Expect(ctx=>ctx.Session).Returns(Session.Object);
Expect(ctx=>ctx.Server).Returns(Server.Object);
Expect(ctx=>ctx.User).Returns(User.Object);
返回context.Object;
}
这是的增强版本。这是moq2.0代码;语法在3中略有不同。我使用的是Steve Sanderson在他的。。。我现在在道德上左右为难,是否可以在这里发布代码。我可以用一个高度精简的版本来折衷一下吗?;) 因此,这可以很容易地被重用,创建一个类似于下面的类,您将通过您的控制器。这将设置模拟并将其设置为控制器的ControllerContext
public class ContextMocks
{
public Moq.Mock<HttpContextBase> HttpContext { get; set; }
public Moq.Mock<HttpRequestBase> Request { get; set; }
public RouteData RouteData { get; set; }
public ContextMocks(Controller controller)
{
//define context objects
HttpContext = new Moq.Mock<HttpContextBase>();
HttpContext.Setup(x => x.Request).Returns(Request.Object);
//you would setup Response, Session, etc similarly with either mocks or fakes
//apply context to controller
RequestContext rc = new RequestContext(HttpContext.Object, new RouteData());
controller.ControllerContext = new ControllerContext(rc, controller);
}
}
看起来与Craig的例子非常相似,但这是MOQv3。为此,我不得不向史蒂夫·桑德森(Steve Sanderson)献计献策——我正以此为基础测试各种传统上难以测试的东西:cookies、会话、请求方法、查询字符串等等 是的,谢谢,但我使用的是Moq 3.1.416.3,所以查看该版本的语法会非常有帮助。主要是因为,很明显,如果我理解正确的话,3.x中的“设置”属性有点不同。感谢您的示例。
request.Expect(req=>req.ApplicationPath)。返回(“~/”
应该是request.Expect(req=>req.ApplicationPath)。返回(“/”我有他的书,但几天前才拿到,所以我想我还没说到那部分。如果你能给我指一下那本书中你从中获得示例代码的那一部分,那就太棒了。非常感谢。看看第九章的结尾。我没有它在我面前,但这似乎是它在亚马逊上的书的目录浏览。找到它。这正是我所需要的。现在一切都好了。非常感谢。这是一个很好的模式,比我在过去需要在//define context objects:Request=new Moq.Mock()上面添加的通过ctor注入上下文包装器要好得多;
public class ContextMocks
{
public Moq.Mock<HttpContextBase> HttpContext { get; set; }
public Moq.Mock<HttpRequestBase> Request { get; set; }
public RouteData RouteData { get; set; }
public ContextMocks(Controller controller)
{
//define context objects
HttpContext = new Moq.Mock<HttpContextBase>();
HttpContext.Setup(x => x.Request).Returns(Request.Object);
//you would setup Response, Session, etc similarly with either mocks or fakes
//apply context to controller
RequestContext rc = new RequestContext(HttpContext.Object, new RouteData());
controller.ControllerContext = new ControllerContext(rc, controller);
}
}
[Test]
Public void test()
{
var mocks = new ContextMocks(controller);
var req = controller.Request;
//do some asserts on Request object
}