This is my Action for my Login Controller. I am able to mock the action using Moq.
But i get an error when it hits this.HttpContext.Response.Cookies.Set(new HttpCookie("AcceptedDoDNotice") { Expires = DateTime.Now.AddDays(-1) });
Error:Additional information: Object reference not set to an instance of an object.
How do i Mock the cookie so i wont get the error above?
public ActionResult Login(LoginViewModel model)
{
if (ModelState.IsValid)
{
var user = _uow.UserRepository.FindLogin(model.Email, model.Password);
if (user != null)
{
_uow.UserRepository.UpdateLastLoginDate(user);
_uow.SaveChanges();
this.HttpContext.Response.Cookies.Set(new HttpCookie("MyCookie") { Expires = DateTime.Now.AddDays(-1) });
if (user.UserLevel.IsAdmin)
return RedirectToAction("Index", "Administrator");
}
else
{
ModelState.AddModelError("", "Invalid username or password.");
}
}
return View(model);
}
The Moq test is below:
//Arrange
var model = new LoginViewModel();
model.Email = realEmail;
model.Password = realPassword;
//Act
var loginController = new LoginController();
var result = loginController.Login(model) as RedirectToRouteResult;
var actual = result.RouteValues["controller"].ToString();
//Assert
actual.Should().Be("Administrator");
You need to mock the controller context. This will allow you to provide a mocked response which in turn provides a cookie collection that you control. You can then see exactly which cookies were set on the response.
var cookieCollection = new HttpCookieCollection { };
var response = new Mock<HttpResponseBase>();
response.SetupGet(r => r.Cookies).Returns(cookieCollection);
var context = new Mock<HttpContextBase>();
context.SetupGet(x => x.Response).Returns(response.Object);
var loginController = new LoginController();
loginController.ControllerContext = new ControllerContext(context.Object, new RouteData(), loginController);
var model = new LoginModel { };
var result = loginController.Login(model) as RedirectToRouteResult;
var actual = result.RouteValues["controller"].ToString();
//Assert
actual.Should().Be("Administrator");
cookieCollection.Should().HaveCount(1);
// other assertions about your cookie
Related
I am using the default ASP.NET MVC, Identity template... I want to send a confirmation email to my clients.
The default implementation which comes with a new project template, has a Register Method in AccountController.cs
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Email.Trim(), Email = model.Email.Trim(), FirstName = model.FirstName.Trim(), LastName = model.LastName.Trim() };
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await SignInManager.SignInAsync(user, isPersistent:false, rememberBrowser:false);
// Send an email with this link
string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
string message = "Please confirm your account by clicking here";
await UserManager.SendEmailAsync(user.Id, "Confirm your account", HttpUtility.UrlEncode(message));
return RedirectToAction("Index", "Home");
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
There is a call to UserManager.SendEmailAsync, now this method is defined in Microsoft.AspNet.Identity and I don't want to change it.
The actual send email function is in IdentityConfig.cs
public class SendGridEmailService : IIdentityMessageService
{
public async Task SendAsync(IdentityMessage message)
{
var apiKey = ConfigurationManager.AppSettings["SendGridApiKey"];
var client = new SendGridClient(apiKey);
var msg = new SendGridMessage()
{
From = new EmailAddress("info#mycompany.com", "DX Team"),
Subject = message.Subject,
PlainTextContent = message.Body,
HtmlContent = message.Body
};
msg.TemplateId = /* I want to pass templateId here */
msg.Personalizations[0].Substitutions.Add("confirmurl", /* I want to pass Username here */);
msg.Personalizations[0].Substitutions.Add("confirmurl", /* I want to pass confirm url here */);
msg.AddTo(new EmailAddress("info#mycompant.com", "Test User"));
var response = await client.SendEmailAsync(msg);
}
}
Now as you see, I am using Sendgrid to send email... so I don't want a message.body to email... I have made some templates and I I want to pass teplate Id with some substituation tags, like username to be replaced in the template.
So I don't want this generic SendAsync method... I want something like
SendGridAsync(SendGridMessage message)
Is it possible to add this method, so I can choose when to call SendAsync and when to call SendGridAsync?
You don't need to use the built in mail service, especially when you want to do something that's a little more complicated.
Define your own messaging service:
public interface IMyMessageService
{
Task SendConfirmationMessage(string confirmUrl, string to)
// define methods for other message types that you want to send
}
public class MyMessageServie : IMyMessageService
{
public async Task SendConfirmationMessage(string confirmUrl, string to)
{
var apiKey = ConfigurationManager.AppSettings["SendGridApiKey"];
var client = new SendGridClient(apiKey);
var msg = new SendGridMessage()
{
From = new EmailAddress("info#mycompany.com", "DX Team"),
Subject = message.Subject,
PlainTextContent = message.Body,
HtmlContent = message.Body
};
msg.TemplateId = /* I want to pass templateId here */
msg.Personalizations[0].Substitutions.Add("confirmurl", confirmUrl);
msg.AddTo(new EmailAddress(to, "Test User"));
var response = await client.SendEmailAsync(msg);
}
}
Register IMyMessageService in your DI framework, and inject it into the controller where the emails are being sent from (e.g. the AccountController).
Now, your register action would look like this (assumes I've injected IMyMessageService and have an instance in _myMessageService):
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Email.Trim(), Email = model.Email.Trim(), FirstName = model.FirstName.Trim(), LastName = model.LastName.Trim() };
var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await SignInManager.SignInAsync(user, isPersistent:false, rememberBrowser:false);
// Send an email with this link
string code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
// USE YOUR MESSAGE SERVICE
await _myMessageService.SendConfirmationMessage(callbackUrl, user.Email);
return RedirectToAction("Index", "Home");
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
I have merged my database with MVC asp.net Identity database and i want to creat a new user using asp.net identity from other controller ,but i could not successfully add the user even my code work without error this is the code:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "Id,Email,EmailConfirmed,Password,SecurityStamp,PhoneNumber,PhoneNumberConfirmed,TwoFactorEnabled,LockoutEndDateUtc,LockoutEnabled,AccessFailedCount,UserName")] AspNetUsers aspNetUsers)
{
if (ModelState.IsValid)
{
// ApplicationUserManager manager = new ApplicationUserManager(new UserStore<ApplicationUser>());
// var manager = HttpContext.Current.GetOwinContext().GetUserManager<UserManager<User>>();
var store = new UserStore<ApplicationUser>();
var manager = new ApplicationUserManager(store);
var user = new ApplicationUser() { Email = aspNetUsers.Email, UserName = aspNetUsers.UserName };
var result= manager.CreateAsync(user, aspNetUsers.PasswordHash);
manager.Create(user, aspNetUsers.Password);
// db.AspNetUsers.Add(aspNetUsers);
// db.SaveChanges();
return RedirectToAction("Index");
}
return View(aspNetUsers);
}
var store = new UserStore<ApplicationUser>(new ApplicationDbContext());
ApplicationUserManager _userManager = new ApplicationUserManager(store);
var manger = _userManager ?? HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
var user = new ApplicationUser() { Email = aspNetUsers.Email, UserName = aspNetUsers.UserName };
var usmanger= manger.Create(user, aspNetUsers.PasswordHash);
I have this function and unit test.
ProfileController Code
[HttpPost]
public ActionResult Edit(int? id)
{
var redirectUrl = new UrlHelper(Request.RequestContext).Action("Index", "Profile", new { id = 0 });
return Json(new { Url = redirectUrl });
}
unit test code
[TestMethod]
public void TestDetailsViewData()
{
var controller = new ProfileController(_Profile);
var result = controller.Edit(1) as ViewResult;
var profile = (VIEWMODELS.Customer.Profile)result.ViewData.Model;
Assert.AreEqual("Testor", profile.cardName);
}
i would like to test this function and this function will redirect to index page and return ViewPage with data. But the problem is when i run this unit test code i got Null exception at this line ,because of the Request is NULL
var redirectUrl = new UrlHelper(Request.RequestContext).Action("Index", "Profile", new { id = 0 });
so may i know how could i test this?
Updated with Moq function
After further reading and get some sample code from here it seem request able to filled with value but now the RequestContext is NULL, anyone can point me to right place for me to study?
[TestMethod]
public void TestDetailsViewData()
{
var request = new Mock<HttpRequestBase>();
request.SetupGet(x => x.Headers).Returns(
new System.Net.WebHeaderCollection {
{"X-Requested-With", "XMLHttpRequest"}
});
var context = new Mock<HttpContextBase>();
context.SetupGet(x => x.Request).Returns(request.Object);
//context.SetupGet(x => x.Request.RequestContext ).Returns(request.Object.RequestContext);
var controller = new ProfileController(_Profile);
controller.ControllerContext = new ControllerContext(context.Object, new RouteData(), controller);
controller.Request.RequestContext = context.Object.Request.RequestContext;
var result = controller.Edit(1) as ViewResult;
var profile = (VIEWMODELS.Customer.Profile)result.ViewData.Model;
Assert.AreEqual("testor", profile.cardName);
}
The error is occurring because the request is not defined in Test method.I think you have to use visual studio fakes.
https://msdn.microsoft.com/en-us/library/hh549175.aspx
i have code like this in my businesslogic class:
if (userList != null) {
pass = userList.Password;
}
else
{
var context = new RequestContext(
new HttpContextWrapper(System.Web.HttpContext.Current),
new RouteData());
var urlHelper = new UrlHelper(context);
var url = urlHelper.Action("Login", "Account");
// how to throw tempdata like this to: TempData["message"] = "Error";
System.Web.HttpContext.Current.Response.Redirect(url);
}
can i possible to throw tempdata from businesslogic class to controller?
I have a controller in C# using the ASP.Net MVC framework
public class HomeController:Controller{
public ActionResult Index()
{
if (Request.IsAjaxRequest())
{
//do some ajaxy stuff
}
return View("Index");
}
}
I got some tips on mocking and was hoping to test the code with the following and RhinoMocks
var mocks = new MockRepository();
var mockedhttpContext = mocks.DynamicMock<HttpContextBase>();
var mockedHttpRequest = mocks.DynamicMock<HttpRequestBase>();
SetupResult.For(mockedhttpContext.Request).Return(mockedHttpRequest);
var controller = new HomeController();
controller.ControllerContext = new ControllerContext(mockedhttpContext, new RouteData(), controller);
var result = controller.Index() as ViewResult;
Assert.AreEqual("About", result.ViewName);
However I keep getting this error:
Exception
System.ArgumentNullException:
System.ArgumentNullException : Value
cannot be null. Parameter name:
request at
System.Web.Mvc.AjaxRequestExtensions.IsAjaxRequest(HttpRequestBase
request)
Since the Request object on the controller has no setter. I tried to get this test working properly by using recommended code from an answer below.
This used Moq instead of RhinoMocks, and in using Moq I use the following for the same test:
var request = new Mock<HttpRequestBase>();
// Not working - IsAjaxRequest() is static extension method and cannot be mocked
// request.Setup(x => x.IsAjaxRequest()).Returns(true /* or false */);
// use this
request.SetupGet(x => x.Headers["X-Requested-With"]).Returns("XMLHttpRequest");
var context = new Mock<HttpContextBase>();
context.SetupGet(x => x.Request).Returns(request.Object);
var controller = new HomeController(Repository, LoginInfoProvider);
controller.ControllerContext = new ControllerContext(context.Object, new RouteData(), controller);
var result = controller.Index() as ViewResult;
Assert.AreEqual("About", result.ViewName);
but get the following error:
Exception System.ArgumentException:
System.ArgumentException : Invalid
setup on a non-overridable member: x
=> x.Headers["X-Requested-With"] at Moq.Mock.ThrowIfCantOverride(Expression
setup, MethodInfo methodInfo)
Again, it seems like I cannot set the request header.
How do I set this value, in RhinoMocks or Moq?
Using Moq:
var request = new Mock<HttpRequestBase>();
// Not working - IsAjaxRequest() is static extension method and cannot be mocked
// request.Setup(x => x.IsAjaxRequest()).Returns(true /* or false */);
// use this
request.SetupGet(x => x.Headers).Returns(
new System.Net.WebHeaderCollection {
{"X-Requested-With", "XMLHttpRequest"}
});
var context = new Mock<HttpContextBase>();
context.SetupGet(x => x.Request).Returns(request.Object);
var controller = new YourController();
controller.ControllerContext = new ControllerContext(context.Object, new RouteData(), controller);
UPDATED:
Mock Request.Headers["X-Requested-With"] or Request["X-Requested-With"] instead of Request.IsAjaxRequest().
For anyone using NSubstitute I was able to modify the above answers and do something like this... (where Details is the Action method name on the controller)
var fakeRequest = Substitute.For<HttpRequestBase>();
var fakeContext = Substitute.For<HttpContextBase>();
fakeRequest.Headers.Returns(new WebHeaderCollection { {"X-Requested-With", "XMLHttpRequest"}});
fakeContext.Request.Returns(fakeRequest);
controller.ControllerContext = new ControllerContext(fakeContext, new RouteData(), controller);
var model = new EntityTypeMaintenanceModel();
var result = controller.Details(model) as PartialViewResult;
Assert.IsNotNull(result);
Assert.AreEqual("EntityType", result.ViewName);
Here is a working solution using RhinoMocks. I've based it on a Moq solution I found at http://thegrayzone.co.uk/blog/2010/03/mocking-request-isajaxrequest/
public static void MakeAjaxRequest(this Controller controller)
{
MockRepository mocks = new MockRepository();
// Create mocks
var mockedhttpContext = mocks.DynamicMock<HttpContextBase>();
var mockedHttpRequest = mocks.DynamicMock<HttpRequestBase>();
// Set headers to pretend it's an Ajax request
SetupResult.For(mockedHttpRequest.Headers)
.Return(new WebHeaderCollection() {
{"X-Requested-With", "XMLHttpRequest"}
});
// Tell the mocked context to return the mocked request
SetupResult.For(mockedhttpContext.Request).Return(mockedHttpRequest);
mocks.ReplayAll();
// Set controllerContext
controller.ControllerContext = new ControllerContext(mockedhttpContext, new RouteData(), controller);
}
Is AjaxRequest is an extension method. So you can do it the following way using Rhino:
protected HttpContextBase BuildHttpContextStub(bool isAjaxRequest)
{
var httpRequestBase = MockRepository.GenerateStub<HttpRequestBase>();
if (isAjaxRequest)
{
httpRequestBase.Stub(r => r["X-Requested-With"]).Return("XMLHttpRequest");
}
var httpContextBase = MockRepository.GenerateStub<HttpContextBase>();
httpContextBase.Stub(c => c.Request).Return(httpRequestBase);
return httpContextBase;
}
// Build controller
....
controller.ControllerContext = new ControllerContext(BuildHttpContextStub(true), new RouteData(), controller);
Looks like you are looking for this,
var requestMock = new Mock<HttpRequestBase>();
requestMock.SetupGet(rq => rq["Age"]).Returns("2001");
Usage in Controller :
public ActionResult Index()
{
var age = Request["Age"]; //This will return 2001
}
In current .NET (v 5):
var controller = new SomeController(); // SomeController that inherits Microsoft.AspNetCore.Mvc.ControllerBase
var httpContext = new DefaultHttpContext(); // DefaultHttpContext class is part of Microsoft.AspNetCore.Http namespace
httpContext.Request.Headers.Add("origin", "0.0.0.1"); // Add your custom headers to request
controller.ControllerContext.HttpContext = httpContext;
You need to mock HttpContextBase and put it into your ControllerContext property, like that:
controller.ControllerContext =
new ControllerContext(mockedHttpContext, new RouteData(), controller);
To make IsAjaxRequest() to return false during Unit test you need to setup Request Headers as well as request collection value both in your test method as given below:
_request.SetupGet(x => x.Headers).Returns(new System.Net.WebHeaderCollection { { "X-Requested-With", "NotAjaxRequest" } });
_request.SetupGet(x=>x["X-Requested-With"]).Returns("NotAjaxRequest");
The reason for setting up both is hidden in implementation of IsAjaxRequest() which is given below:
public static bool IsAjaxRequest(this HttpRequestBase request)<br/>
{
if (request == null)
{
throw new ArgumentNullException("request");
}
return ((request["X-Requested-With"] == "XMLHttpRequest") || ((request.Headers != null) && (request.Headers["X-Requested-With"] == "XMLHttpRequest")));
}
It uses both request Collection and header this is why we need to create setup for both Header and Request Collection.
this will make the request to return false when it is not a ajax request. to make it return true you can do the following:
_httpContext.SetupGet(x => x.Request["X-Requested-With"]).Returns("XMLHttpRequest");
I found other way to add a HttpRequestMessage object into your request during Web API as follow
[Test]
public void TestMethod()
{
var controllerContext = new HttpControllerContext();
var request = new HttpRequestMessage();
request.Headers.Add("TestHeader", "TestHeader");
controllerContext.Request = request;
_controller.ControllerContext = controllerContext;
var result = _controller.YourAPIMethod();
//Your assertion
}
(A bit late to the party but I went for a different route so thought I'd share)
To go for a pure code/mocking way of testing this without creating mocks for Http classes I implemented an IControllerHelper which has an Initialise method which takes the Request as a parameter and then exposed properties I want eg:
public interface IControllerHelper
{
void Initialise(HttpRequest request);
string HostAddress { get; }
}
public class ControllerHelper : IControllerHelper
{
private HttpRequest _request;
public void Initialise(HttpRequest request)
{
_request = request;
}
public string HostAddress => _request.GetUri().GetLeftPart(UriPartial.Authority);
}
Then in my controller I call initialise at the start of the method:
_controllerHelper.Initialise(Request);
And then my code is only dependent on mockable dependacies.
return Created(new Uri($"{_controllerHelper.HostName}/api/MyEndpoint/{result.id}"), result);
For functional tests I just override the iControllerHelper in the composition for a substitute.