MVC Unit testing [Authorize(Roles="Role")] - asp.net-mvc

So I have been googling this for a couple of hours and I am yet to find a working solution.
Here are a couple of questions I have found that paint the picture of what I've been doing but none give me a working answer.
How do I unit test a controller method that has the [Authorize] attribute applied?
Unit testing ASP.Net MVC Authorize attribute to verify redirect to login page
What I am trying to do is to write a unit that that checks the [Authorise(Roles="Role")] attribute on my controller actually allows/denies access to the controller based on the current user belonging/not belonging to a specific role.
The code below always returns the view even when I set IsInRole to false hence I figure it is ignoreing the Authorise attribute.
[TestMethod]
public void Auth_User_Can_Access()
{
//this test mocks a user and submits it as part of the context to the controller
//Arrange
Mock<IPrincipal> mockP = new Mock<IPrincipal>();
mockP.SetupGet(p=>p.Identity.Name).Returns("UnitTesting");
mockP.Setup(p=>p.IsInRole("Role")).Returns(false); //"Role" is not the actual role name.
Mock<ControllerContext> mockC = new Mock<ControllerContext>();
mockC.SetupGet(p=>p.HttpContext.User).Returns(mockP.Object);
mockC.SetupGet(p=>p.HttpContext.Request.IsAuthenticated).Returns(true);
AppsController target = new AppsController(mock.Object);
target.ControllerContext = mockC.Object;
// Act
ViewResult result = target.Index() as ViewResult;
// Assert
Assert.IsNotNull(result);
}
I'm clearly missing something here.
For completeness here is the start of my Controller code also
[Authorize(Roles = "Role")]
public class AppsController : Controller
{
private IAppRepository db;
public AppsController (IAppRepository appRepository)
{
db = appRepository;
}
// GET: Apps
public ViewResult Index()
{
return View(db.Apps.ToList());
}

You can write your unit test with the help of Xania.AspNet.Simulator
new AppsController(appRepo).Action(c => c.Index())
.Authenticate("user1", new []{"Role"})
.Authorize().Should().BeNull(); // authorized
new AppsController(appRepo).Action(c => c.Index())
.Authenticate("user1", new []{"Dummy"})
.Authorize().Should().BeOfType<HttpUnauthorizedResult>(); // not authorized
for more information please refer to http://www.codeproject.com/Tips/850277/ASP-NET-MVC-End-to-End-Integration-Testing

Related

How to create a unit test that tests that a page requires authorization in mvc5

I am trying to work out how to write a unit test that will test that a controllers authorization is working. IE a user that is not logged in can't access the page. Does anybody know how to go about this? I am having trouble finding examples.
something like this (Pseudo Code)
[TestMethod]
public void Get_Auth_Page()
{
be_a_user_thats_not_logged_in = true;
// Arrange
MyController controller = new MyController();
// Act
var result = controller.Index();
// Assert
if(result.httpstatus == 403)
Assert.True();
}
If you are simply decorating your action method with [Authorize], you can just have a test that asserts the existence of the attribute:
[TestMethod]
public void Index_action_requires_authentication()
{
// If Index is overloaded, you might need to filter by argument list
MethodInfo indexMethod = typeof(MyController).GetMethod("Index");
bool requiresAuthentication =
Attribute.IsDefined(indexMethod, typeof(AuthorizeAttribute));
Assert.IsTrue(requiresAuthentication);
}
Obviously you aren't testing the Authorize implementation here, but it does serve to both document and to protect against developers accidentally removing it.
If you are running custom code, then you are probably returning a HttpStatusCodeResult, so you can just check for that:
public void Index_action_requires_authentication()
{
ActionResult result = new MyController().Index();
HttpStatusCodeResult statusCodeResult = result as HttpStatusCodeResult;
Assert.IsNotNull(statusCodeResult);
Assert.AreEqual(403, statusCodeResult.StatusCode);
}
If you are manually writing to the HttpResponse (Response.StatusCode or Response.Headers), then you'll need to mock the HttpContextBase as others have described.

Test if save method is hit in unit test

I'm starting with unit testing in the asp.net mvc 4 framework.
I got a repository with basic crud methods and a save method. When I create a unit test I create a test repository and test if e.g. a item to the collection is added. That all goes smoothly but I cannot test if the save method is hit.
I tried to add a boolean property to the test repository which will be set to true if .save() is hit. But then I need to change the interface, and also the database repository. Which is in my opinion neither practical nor best practice.
What is the best method to test this? Thank you in advance for your answer.
My code:
the fake repository:
public class TestUserRepository : IUserManagementRepository
{
/// <summary>
/// entries used used for testing
/// </summary>
private List<User> _entities;
/// <summary>
/// constructor
/// </summary>
public TestUserRepository()
{
_entities = new List<User>();
_entities.Add(new User
{
Id = 1,
InsertDate = DateTime.Now,
LastUpdate = DateTime.Now,
Username = "TestUserName",
Password = "TestPassword"
});
}
...
public void Create(User task)
{
_entities.Add(task);
}
public void Save()
{
//do nothing
}
}
the controller to test:
[HttpPost]
public ActionResult Create(User user)
{
if (ModelState.IsValid)
{
_repository.Create(user);
_repository.Save();
return RedirectToAction("Index");
}
else
{
return View(user);
}
}
and the test
[TestMethod()]
public void CreateTest()
{
IUserManagementRepository repository = new TestUserRepository();
UserController controller = new UserController(repository);
User user = new User { Username = "UnitTestUserName", InsertDate = DateTime.Now, LastUpdate = DateTime.Now, Password = "Password" };
ActionResult actionResult = controller.Create(user);
User returnedUser = repository.FindBy(u => u.Username == "UnitTestUserName").First<User>();
Assert.IsNotNull(actionResult);
Assert.AreEqual(user, returnedUser);
}
You must be careful not to write a bunch of unit tests that just test your test repository.
Consider the following scenario:
You have a service method, that is supposed to add an item to your repository.
Your unit test calls this method, and you should verify that the appropriate "AddX" method was called on the repository.
This is a valid unit test scenario, to test it you can use your test repository. Since it is your test object, you have full control over it. You can expose properties such as "AddXMethodCallCount" or something similar.
Over time you will find yourself writing a lot of test code that is pretty much boilerplate. The alternative, which I strongly recommend, is to use a mocking framework:
https://stackoverflow.com/questions/37359/what-c-sharp-mocking-framework-to-use
It takes some getting used to, but once you get it, it will speed up your unit testing significantly.
If you don't want to use mocking yet, but want to still achieve your goal of verifying whether or not Save() is called, I would suggest just adding a publicly exposed SaveMethodCallCount property:
public class TestUserRepository : IUserManagementRepository
{
...
public SaveMethodCallCount {get; set;}
...
public void Save()
{
SaveMethodCallCount++;
}
}
This works, because in your unit test you can actually say:
TestUserRepository repository = new TestUserRepository();
The UserController does not care, as long as the passed in parameter implements the IUserManagementRepository interface. The controller interacts with the repository object through the interface, but the unit test does not have to, and the TestUserRepository, being a test class, is allowed to have much more functionality, that does not have to be exposed through the interface.
So your test could look something like:
[TestMethod()]
public void CreateTest()
{
TestUserRepository repository = new TestUserRepository();
UserController controller = new UserController(repository);
User user = new User { Username = "UnitTestUserName", InsertDate = DateTime.Now, LastUpdate = DateTime.Now, Password = "Password" };
ActionResult actionResult = controller.Create(user);
User returnedUser = repository.FindBy(u => u.Username == "UnitTestUserName").First<User>();
Assert.IsNotNull(actionResult);
Assert.AreEqual(user, returnedUser);
Assert.AreEqual(1, repository.SaveMethodCallCount);
}
To make my example complete, let me show you what this would look like if you used a mocking framework, like Moq. You can see some more examples here. The example test method uses Moq and Arrange/Act/Assert, and tests only one thing - that Save() is called when Create() is called.
[TestMethod()]
public void Test_SaveCalledWhenCreateCalled()
{
// Arrange
// First, instead of creating an instance of your test class, you create a mock repository.
// In fact, you don't need to write any code, the mocking framework handles it.
var mockRepository = new Mock<IUserManagementRepository>();
// and pass the mock repository (which implements the IUserManagementRepository) to your controller
UserController controller = new UserController(mockRepository);
// Act
ActionResult actionResult = controller.Create(user);
// Assert
// see how easy it is to do with a mocking framework:
mockRepository.Verify(rep => rep.Save(), Times.AtLeastOnce());
}

Response Object is a null reference in my Controller's action method

I'm developing a webapp using ASP.NET MVC and C#. And I'm creating a unit test for this webapp using NUnit and Rhino Mock. My problem is that I have a Response object in my controller's action method and when I execute my unit test my test is failing because the Response object is a null reference.
Do I need to separate this Response object call in my actions or there is a better way to resolve this?
public ActionResult Login( string user, string password )
{
Response.Cookies[ "cookie" ].Value = "ck";
...
return View();
}
Please advise.
Many thanks.
What the controller really lacks is its HttpContext. In a test method it should be added explicitly if needed:
[Test]
public void TestMethod()
{
// Assume the controller is created once for all tests in a setup method
_controller.ControllerContext.HttpContext = new DefaultHttpContext();
var result = _controller.Login("username", "verySaf3Passw0rd");
// Asserts here
}
This is one of the annoying points where ASP.NET MVC is not as testable and loosely coupled as it could be. See this question for some suggestions how to mock the HTTP context objects.
I ended up creating a real response that my mock context returns like this...
Mock<HttpSessionStateBase> mockSession;
Mock<ControllerContext> mockContext;
Mock<ISessionProvider> mockSessionProvider;
HttpResponse testResponse;
MyController controller;
[TestInitialize]
public void Initialize()
{
testResponse = new HttpResponse(TextWriter.Null);
mockContext = new Mock<ControllerContext>();
mockSession = new Mock<HttpSessionStateBase>();
mockContext.Setup(x => x.HttpContext.Session).Returns(mockSession.Object);
mockContext.Setup(x => x.HttpContext.Response).Returns(new HttpResponseWrapper(testResponse));
controller = new MyController();
controller.ControllerContext = mockContext.Object;
}

Simple Question: Setup mock for ajax request in asp.net mvc

I am new in unit test and MVC development.
I have a question for using moq for unit testing in asp.net mvc. I have a controller which accepts an ajax action:
[HttpPost,Authorize]
public ActionResult GrabLink()
{
string username = HttpContext.User.Identity.Name;
string rssUrl = Request.Params["Grablink"].ToString();
...}
This action deals with the http request which I generate from the view:
var mockRequest = new Moq.Mock<HttpRequestBase>();
but I can not find a way to define the parameters I used in the class. Also, is there any way to use the value binding provider directly to pass the value to the controller if I would like to do an ajax post?
I am a newbie in handling web request. If you have some good tutorial for better understanding the Http request (as well as the Httpcontext and related classes in asp.net) please post here. Thank you very much!
This works very well for me:
var controller = new HomeController();
var context = new Mock<HttpContextBase>(MockBehavior.Strict);
var controllerContext = new Mock<ControllerContext>();
controllerContext.SetupGet(x => x.HttpContext.User.Identity.Name)
.Returns("TestUser");
controllerContext.SetupGet(x => x.HttpContext.User.Identity.IsAuthenticated)
.Returns(true);
controllerContext.SetupGet(x => x.HttpContext.Request.IsAuthenticated)
.Returns(true);
controller.ControllerContext = controllerContext.Object;
// As a bonus, instantiate the Url helper to allow creating links
controller.Url = new UrlHelper(
new RequestContext(context.Object, new RouteData()), new RouteCollection());
This will allow you to initialize any user you want as an authenticated user, and the last line will allow you to user the Url helper within the controller even though you're calling it from a unit test.
As Scott said HttpContext makes Controllers hard to test. Anyway he's got a pretty solution at here.
BTW why didn't you make rssUrl a parameter if it is assigning by POST or GET?
e.g.
//POST: /GrabLink?rssUrl=bla bla...
[HttpPost,Authorize]
public ActionResult GrabLink(IPrincipal user, string rssUrl) {
string userName = user.Name;
}
Ok, #cem covered your second question very well.
For your first, nerddinner, and If I'm not mistaken, when you create a new Internet Application with Unit test, in Visual Studio, have the following mock classes for HttpContext. Its at the bottom of this file.
You could use these (or create a new Internet App +Tests with VS) and copy all the fake classes for your tests. (I wrote a Moq example below)
It looks like this:
public class MockHttpContext : HttpContextBase {
private IPrincipal _user;
public override IPrincipal User {
get {
if (_user == null) {
_user = new MockPrincipal();
}
return _user;
}
set {
_user = value;
}
}
public override HttpResponseBase Response
{
get
{
return new MockHttpResponse();
}
}
}
public class MockHttpResponse : HttpResponseBase {
public override HttpCookieCollection Cookies
{
get
{
return new HttpCookieCollection();
}
}
}
Not tested, but to Use mock it would look like this:
var fakeReqBase = new Mock<HttpRequestBase>();
fakeReqBase.Setup(f => f.User).Returns(new GenericIdentity("FakeUser"));
//generic identity implements IIdentity
fakeUserRepo.Object;//this returns fake object of type HttpRequestBase
Checkout the Moq Quickstart. Its quite easy to get used to, and the fluent interface really helps.

How do I unit test a controller method that has the [Authorize] attribute applied?

I've searched stackoverflow and googled four a couple of hours and still not found any solution for my "trivial" problem.
If you write unit test for your filtered [Authorize] ActionResult, how do you solve the problem to fake that user is authenticated?
I have a lot of ActionResult methods that are filtered with [Authorize] and I want to test all of my ActionResult methods regardless if they are filtered with [Authorize] or not.
A simple example of what i mean:
[TestMethod]
public void Create_Get_ReturnsView()
{
// Arrange
var controller = new UserController();
// Act
var result = controller.Create();
// Assert
Assert.IsNotNull(result as ViewResult);
}
[Authorize]
public ActionResult Create()
{
return View("Create");
}
As of now the tests don't even hit the ActionResult method because of the [Authorize] filter, exception thrown is: System.NullReferenceException: Object reference not set to an instance of an object.
You need to mock a context for your controller. Try using Moq
Your arrange would then look like:
var controller = new UserController();
var mock = new Mock<ControllerContext>();
mock.SetupGet(x => x.HttpContext.User.Identity.Name).Returns("SOMEUSER");
mock.SetupGet(x => x.HttpContext.Request.IsAuthenticated).Returns(true);
controller.ControllerContext = mock.Object;
You should be able to then do your Act & Assert.
If you haven't already, I would highly recommend looking through NerdDinner as an example MVC site.

Resources