I am using hanselman tutorial to use Moq to create unit tests for my asp.net pages.
I wrote the following code to test for ServerVariables in contextbase request class
HttpContextBase contextbase = MoqHelper.FakeHttpContext();
contextbase.Request.ServerVariables.Add("AUTH_TYPE","Forms"); <-- error here
contextbase.Request.ServerVariables.Add("LOGON_USER", "Tom");
contextbase.Request.ServerVariables.Add("REQUEST_METHOD", "GET");
But I am getting following exception. Please help.
System.NullReferenceException was unhandled by user code Message=Object reference not set to an instance of an object.
How do I create unit test to test server variables?
There are some misprint on Scott Hanselman's page (lowercase class names). So here is how code should look like (I also changed old Expect syntax with new Setup syntax):
public static class MvcMockHelpers
{
public static HttpContextBase FakeHttpContext()
{
var context = new Mock<HttpContextBase>();
var request = new Mock<HttpRequestBase>();
var response = new Mock<HttpResponseBase>();
var session = new Mock<HttpSessionStateBase>();
var server = new Mock<HttpServerUtilityBase>();
context.Setup(ctx => ctx.Request).Returns(request.Object);
context.Setup(ctx => ctx.Response).Returns(response.Object);
context.Setup(ctx => ctx.Session).Returns(session.Object);
context.Setup(ctx => ctx.Server).Returns(server.Object);
return context.Object;
}
}
Back to your case. You see this exception, because when fake HttpContext is created, only its direct properties Request, Response, Session and Server were setup-ed. But you are trying to access property ServerVariables of request mock. So, you need to setup some return results for this property. See example how Scott setups request url for request mock:
public static void SetupRequestUrl(this HttpRequestBase request, string url)
{
if (url == null)
throw new ArgumentNullException("url");
var mock = Mock.Get(request);
mock.Setup(req => req.QueryString)
.Returns(GetQueryStringParameters(url));
mock.Setup(req => req.AppRelativeCurrentExecutionFilePath)
.Returns(GetUrlFileName(url));
mock.Setup(req => req.PathInfo)
.Returns(string.Empty);
}
Main idea here - you cannot use directly contextBase.Request.QueryString you should setup request mock before:
mock.Setup(req => req.QueryString)
.Returns(GetQueryStringParameters(url));
Related
As per last section of the Moq Quickstart defined here, I am trying to configure the following Mock in order to pass Form values to the controller method under test:
var formCollection = new FormCollection(
new System.Collections.Generic.Dictionary<string, Microsoft.Extensions.Primitives.StringValues>()
{
{"mAction", "someAction" },
{"mRefId", "0" }
});
var controllerContext = Mock.Of<ControllerContext>(ctx =>
ctx.HttpContext.Request.Form == formCollection);
controller.ControllerContext = controllerContext;
However, when the run the test, it fails on the Mock.Of<> line with the following error:
System.NotSupportedException : Unsupported expression: mock => mock.HttpContext
Non-overridable members (here: ActionContext.get_HttpContext) may not be used in setup / verification expressions.
What am I missing? Am I not doing it the same as per the example defined in the Quickstart document?
The error is because ControllerContext.HttpContext property is not virtual, so Moq is unable to override it.
Consider using an actual ControllerContext and mocking a HttpContext to assign to the property
var formCollection = new FormCollection(new Dictionary<string, StringValues>()
{
{"mAction", "someAction" },
{"mRefId", "0" }
});
var controllerContext = new ControllerContext() {
HttpContext = Mock.Of<HttpContext>(ctx => ctx.Request.Form == formCollection)
};
controller.ControllerContext = controllerContext;
//...
Or even using DefaultHttpContext and assign the desired value(s)
var formCollection = new FormCollection(new Dictionary<string, StringValues>()
{
{"mAction", "someAction" },
{"mRefId", "0" }
});
HttpContext httpContext = new DefaultHttpContext();
httpContext.Request.Form = formCollection;
var controllerContext = new ControllerContext() {
HttpContext = httpContext
};
controller.ControllerContext = controllerContext;
//...
You need to manually set all properties which are not marked virtual either by explicitly setting them in the lambda, or possibly setting them outside (there is no need to create a concrete object), this works by me at least in version 4.16.1.
Method 1 (when using Mock.Of()):
var mockCtx = Mock.Of<ControllerContext>(ctx =>
ctx.HttpContext == Mock.Of<HttpContext>(hCtx => hCtx.Request.Form
== formCollection))`
NOTE: In case you need to set all properties to be mocked, or do anything that needs Mock.Get() as in this answer you need to do it directly on the HttpContext as in Mock.Get(mockCtx.HttpContext ) and not on the mockCtx.
Method 2 (when using new Mock<>()):
var mockCtx = new Mock<ControllerContext>();
mockCtx.Object.HttpContext = Mock.Of<HttpContext>(hCtx => hCtx.Request.Form
== formCollection);
There is no need to create a concrete object, as method 2 is just doing the same but with a mock object.
Note: This will only work if the property is not readonly.
I am doing a unit test project to test a read method in a controller. I am trying to mock the Repository but I am getting a problem.
There is an App Repository which contains all the Repositories. and another Repository for users:
var repositoriesMock = new Mock<IAppRepositories>();
var userMock = new Mock<UserRepository> ();
repositoriesMock.SetupGet(x => x.Users).Returns(
partnerMock.Object
);
userMock.SetupGet(x => x.GetUserDto(false, 1) ).Returns(
new List<GeschaeftspartnerDto> {user1, user2}.AsQueryable()
);
in the controller:
public ActionResult Read([DataSourceRequest] DataSourceRequest request)
{
var list = this.AppRepositories.Users.GetUserDto(false, 1).ToList();
}
but I am receiving an Error in uerMock.SetupGet
Expression is not a property access: x => x.GetUserDto(False, 1)
what is going on? why am I getting this error?
Try using Mock.Setup instead of Mock.SetupGet.
I want to test my MVC application, and I want to mock HttpContext. I'm using Moq framework, and here is what I've done to mock HttpContext:
[SetUp]
public void Setup()
{
MyUser myUser = new MyUser();
myUser.Id = 1;
myUser.Name = "AutomatedUITestUser";
var fakeHttpSessionState =
new FakeHttpSessionState(new SessionStateItemCollection());
fakeHttpSessionState.Add("__CurrentUser__", myUser);
ControllerContext mockControllerContext = Mock.Of<ControllerContext>(ctx =>
ctx.HttpContext.User.Identity.Name == myUser.Name &&
ctx.HttpContext.User.Identity.IsAuthenticated == true &&
ctx.HttpContext.Session == fakeHttpSessionState &&
ctx.HttpContext.Request.AcceptTypes ==
new string[]{ "MyFormsAuthentication" } &&
ctx.HttpContext.Request.IsAuthenticated == true &&
ctx.HttpContext.Request.Url == new Uri("http://moqthis.com") &&
ctx.HttpContext.Response.ContentType == "application/xml");
_controller = new SomeController();
_controller.ControllerContext = mockControllerContext; //this line is not working
//when I see _controller.ControllerContext in watch, it get's me
//_controller.ControllerContext threw an exception of type System.ArgumentException
}
[Test]
public void Test_ControllerCanDoSomething()
{
// testing an action of the controller
// The problem is, here, System.Web.HttpContext.Current is null
}
Because my application uses Session to hold user data and authentication info in almost every action method, thus I need to set HttpContext and inside it I need to set Session and put __CurrentUser__ inside session, so that action methods would have access to faked logged in user.
However, HttpContext is not set and it's null. I've searched a lot and I couldn't find my answer.
What might be wrong?
Update:
I also test below line, and get same result
_controller.ControllerContext = new ControllerContext(
mockControllerContext.HttpContext, new RouteData(), _controller);
Judging by this answer: Mocking Asp.net-mvc Controller Context
It looks like you need to mock the Request itself, as well as the properties of the request object.
e.g.
var request = new Mock<HttpRequestBase>();
etc (the full code is in the linked answer).
I am working on an asp.net mvc 3.0 application. In unit testing one of the action method in my controller, I was getting an error.
How to mock: Request.Params["FieldName"]
I have included Moq framework, but was not sure how to pass value
Here is my code... Please suggest...
var request = new Mock<System.Web.HttpRequestBase>();
request
.SetupGet(x => x.Headers)
.Returns(
new System.Net.WebHeaderCollection
{
{"X-Requested-With", "XMLHttpRequest"}
});
var context = new Mock<System.Web.HttpContextBase>();
context.SetupGet(x => x.Request).Returns(request.Object);
ValidCodeController target = new ValidCodeController();
target.ControllerContext =
new ControllerContext(context.Object, new RouteData(), target);
Params is a NameValueCollection property that can be set-up in a similar way to Headers:
var requestParams = new NameValueCollection
{
{ "FieldName", "value"}
};
request.SetupGet(x => x.Params).Returns(requestParams);
Another alternative to mocking the Context and all it's dependencies is to abstract the entire context/Params collection in a separate class, and mock that instead. In many cases this will make it easier, and avoids having to mock a complicated object graph:
Ex:
public void MainMethod()
{
var valueInQuestion = ISomeAbstraction.GetMyValue("FieldName");
}
You can now mock the GetMyValue method instead.
I am very, very new to unit testing and am trying to write a test for a pretty simple method:
public class myClass : RequireHttpsAttribute
{
public override void OnAuthorization(AuthoizationContext filterContext)
{
var request = filterContext.HttpContext.Request;
var header = Convert.ToBoolean(request.Headers["Special-Header-Name"]);
if (!(header || request.IsSecureConnection))
{
HandleNonHttpsRequest(filterContext);
}
}
}
This method, which inherits from the RequireHttpsAttribute, checks if a certain header is present from a page, if it's missing or false, and the page is not secure, then it will call HandleNonHttpsRequest, otherwise it does nothing.
We are using Moq and Nunit for testing. I have found some resources to help build a fakeHttpContext with Moq, but honestly I'm not sure how to use it or where to go within my unit tests to ensure that fake HttpContexts are or are not causing the HandleNonHttpsRequest method to call.
I really appreciate any guidance with this issue.
// arrange
var context = new Mock<HttpContextBase>();
var request = new Mock<HttpRequestBase>();
var headers = new NameValueCollection
{
{ "Special-Header-Name", "false" }
};
request.Setup(x => x.Headers).Returns(headers);
request.Setup(x => x.HttpMethod).Returns("GET");
request.Setup(x => x.Url).Returns(new Uri("http://www.example.com"));
request.Setup(x => x.RawUrl).Returns("/home/index");
context.Setup(x => x.Request).Returns(request.Object);
var controller = new Mock<ControllerBase>();
var actionDescriptor = new Mock<ActionDescriptor>();
var controllerContext = new ControllerContext(context.Object, new RouteData(), controller.Object);
var filterContext = new AuthorizationContext(controllerContext, actionDescriptor.Object);
var sut = new myClass();
// act
sut.OnAuthorization(filterContext);
// assert
Assert.IsInstanceOfType(filterContext.Result, typeof(RedirectResult));
var redirectResult = (RedirectResult)filterContext.Result;
Assert.AreEqual("https://www.example.com/home/index", redirectResult.Url);
Yes, I'd use Moq and create a Mock<AuthorizationContext>. You'll need a series of mock objects to setup the fake request, most notably to specify a NameValueCollection of fake headers.
var request = new Mock<HttpRequestBase>();
request.SetupGet(c => c.Headers).Return(new NameValueCollection{ /* initialize values here */});
request.SetupGet(c => c.IsSecureConnection).Return(/*specify true or false depending on your test */);
var httpContext = new Mock<HttpContextBase>();
httpContext.SetupGet(c => c.Request).Return(request.Object);
var filterContext = new Mock<AuthorizationContext>();
filterContext.SetupGet(c => c.HttpContext).Return(httpContext.Object);
var myclass = new myClass();
myClass.OnAuthorization(filterContext.Object);
(sorry if syntax or usage is slightly off; doing this from the top of my head)
You may need to go in and mock any additional members on filterContext that HandleNonHttpsRequest invokes. I have two recommendations for going about this, as it can sometimes be a hassle if the method you are testing is doing lots of complex stuff on filterContext: 1) check visually and, if it's straight forward enough, mock all the invoked pieces 2) create the myClass.OnAuthorizationRequest, but don't implement any code yet other than the call to HandleNonHttpsRequest. Keep running the test and fixing missing/incorrectly mocked members until the test passes. Then implement your actual logic for OnAuthorizationRequest, testing and fixing (rinse repeat) until it passes.
I encountered an issue with the accepted solution using ASP.NET MVC 4. To resolve it I mocked the http context Items attribute otherwise the sut.OnAuthorization was causing an object is undefined exception:
MockHttpContext.Setup(x => x.Items)
.Returns(new System.Collections.Generic.Dictionary<object, object>());