MVC Testing actions that rely on HTTPContext - c#

I have a project where I need to provide action tests. My approuch has been to ensure actions do not rely on anything they do not receive as parameters, maing use of ValueProviders and ModelBinders. As such I would pass in HTTPContextBase etc.
However, I now have an action which uses a static class that is a wrapper around HTTPContext to accesses Session and Identity. Thus it seems I have to mock out HTTPContext to test this action. Not too complicated, I guess, but it just feels wrong.
My gut feeling is that the static class should be redeveloped to be instantiated with HTTPSessionStateBase and IPrinicple and use them as internal stores. Then I could instantiate this wrapper in my action, from action parameters, making the action and the wrapper class much more testing friendly.
Would this be a recommended approuch or does anyone have any other ideas, were I would not have to change my static class to instance ?

I think that using Moq to mock a HttpContext is just the way you might want to try it out.
[TestMethod]
public void Test()
{
var context = new Mock<HttpContextBase>();
var request = new Mock<HttpRequestBase>();
context.Setup(c => c.Request).Returns(request.Object);
HomeController controller = new HomeController();
controller.ControllerContext = new ControllerContext( context , new RouteData(), controller );
....
...........
}
Updated:
In the case if you want to mock HttpSession(as gdoron mentioned in comment). It is not really complicated since you are MOCKING something doesn't means you have to build entire, real object and all of its properties.
Suppose that your controller will
Checks whether user is authenticated.
Gets identity name.
Gets a value from Session["key"].
manipulates cookie.
The code could be like that:
[TestMethod]
public void Test()
{
......
.........
var mockedControllerContext = new Mock<ControllerContext> ();
mockedControllerContext.SetupGet(p => p.HttpContext.Session["key"]).Returns("A value in session");
mockedControllerContext.SetupGet(p => p.HttpContext.Request.IsAuthenticated).Returns(true);
mockedControllerContext.SetupGet(p => p.HttpContext.User.Identity.Name).Returns("An identity name");
mockedControllerContext.SetupGet(p => p.HttpContext.Response.Cookies).Returns(new HttpCookieCollection ());
HomeController controller = new HomeController();
controller.ControllerContext = mockedControllerContext.Object;
.....
......
}

I strongly recommend using MvcContrib - testhelpers
Learn how to use from CodePlex
You can download it from nuget or directly from CodePlex
Good luck!

Related

How to moq HttpContext on Asp net Core

I have an asp .net core project, and practically in each action we use session, my question is how to test it if I don't have sessionRepository. Controller tests crush because session in controller is null. I try to Moq IHttpContextAcessor and it also doesn't work.
I try this:
HttpContext.Current = new HttpContext(new HttpRequest(null, "http://tempuri.org", null), new HttpResponse(null));
but HttpContext doesn't contain the definition for Current. (using Microsoft.AspNetCore.Http;)
Is there any way to moq or test controllers that use HttpContext and sessions?
You can use ControllerContext to set the context to be DefaultHttpContext which you can modify to your needs.
var ctx = new ControllerContext() { HttpContext = new DefaultHttpContext()};
var tested = new MyCtrl();
tested.ControllerContext = ctx;
The controller has an Controller context which you can set (i used the default one) :
Controller.ControllerContext = new ControllerContext
{
HttpContext = new DefaultHttpContext()
};
After time I think is bad idea to moq Session, better way is to create a IOC container, for example we create ISessionManager interface with methods which return stored in session objects:
public class SessionManager:ISessionManager{
public User GetUser(){
User usr= JsonConvert.DeserializeObject<User>(HttpContext.Session.GetString("USER"));
return usr;
}
***here we get data from session***
}
for UnitTest we just create a new class which implement ISessionManager and use it for test Controller's.
public class SessionManagerTest:ISessionManager{
public User GetUser(){
User usr=new User();
...initialize all fields
return usr;
}
******
}

Unit Testing for Redirection Using Global Authorize Attribute [duplicate]

This is probably going to turn out to be a case of just needing another pair of eyes. I must be missing something, but I cannot figure out why this kind of thing cannot be tested for. I'm basically trying to ensure that unauthenticated users cannot access the view by marking the controller with the [Authorize] attribute and I'm trying to tests this using the following code:
[Fact]
public void ShouldRedirectToLoginForUnauthenticatedUsers()
{
var mockControllerContext = new Mock<ControllerContext>()
{ DefaultValue = DefaultValue.Mock };
var controller = new MyAdminController()
{ControllerContext = mockControllerContext.Object};
mockControllerContext.Setup(c =>
c.HttpContext.Request.IsAuthenticated).Returns(false);
var result = controller.Index();
Assert.IsAssignableFrom<RedirectResult>(result);
}
The RedirectResult I'm looking for is some kind of indication that the user is being redirected to the login form, but instead a ViewResult is always returned and when debugging I can see that the Index() method is successfully hit even though the user is not authenticated.
Am I doing something wrong? Testing at the wrong level? Should I rather be testing at the route level for this kind of thing?
I know that the [Authorize] attribute is working, because when I spin up the page, the login screen is indeed forced upon me - but how do I verify this in a test?
The controller and index method are very simple just so that I can verify the behaviour. I've included them for completeness:
[Authorize]
public class MyAdminController : Controller
{
public ActionResult Index()
{
return View();
}
}
Any help appreciated...
You are testing at the wrong level. The [Authorize] attribute ensures that the routing engine will never invoke that method for an unauthorized user - the RedirectResult will actually be coming from the route, not from your controller method.
Good news is - there's already test coverage for this (as part of the MVC framework source code), so I'd say you don't need to worry about it; just make sure your controller method does the right thing when it gets called, and trust the framework not to call it in the wrong circumstances.
EDIT: If you want to verify the presence of the attribute in your unit tests, you'll need to use reflection to inspect your controller methods as follows. This example will verify the presence of the Authorize attribute on the ChangePassword POST method in the 'New ASP.NET MVC 2 Project' demo that's installed with MVC2.
[TestFixture]
public class AccountControllerTests {
[Test]
public void Verify_ChangePassword_Method_Is_Decorated_With_Authorize_Attribute() {
var controller = new AccountController();
var type = controller.GetType();
var methodInfo = type.GetMethod("ChangePassword", new Type[] { typeof(ChangePasswordModel) });
var attributes = methodInfo.GetCustomAttributes(typeof(AuthorizeAttribute), true);
Assert.IsTrue(attributes.Any(), "No AuthorizeAttribute found on ChangePassword(ChangePasswordModel model) method");
}
}
Well you might be testing at the wrong level but its the test that makes sense. I mean, if I flag a method with the authorize(Roles="Superhero") attribute, I don't really need a test if I flagged it. What I (think I) want is to test that an unauthorized user doesn't have access and that an authorized user does.
For a unauthorized user a test like this:
// Arrange
var user = SetupUser(isAuthenticated, roles);
var controller = SetupController(user);
// Act
SomeHelper.Invoke(controller => controller.MyAction());
// Assert
Assert.AreEqual(401,
controller.ControllerContext.HttpContext.Response.StatusCode, "Status Code");
Well, it's not easy and it took me 10 hours, but here it is. I hope someone can benefit from it or convince me to go into another profession. :) (BTW - I'm using rhino mock)
[Test]
public void AuthenticatedNotIsUserRole_Should_RedirectToLogin()
{
// Arrange
var mocks = new MockRepository();
var controller = new FriendsController();
var httpContext = FakeHttpContext(mocks, true);
controller.ControllerContext = new ControllerContext
{
Controller = controller,
RequestContext = new RequestContext(httpContext, new RouteData())
};
httpContext.User.Expect(u => u.IsInRole("User")).Return(false);
mocks.ReplayAll();
// Act
var result =
controller.ActionInvoker.InvokeAction(controller.ControllerContext, "Index");
var statusCode = httpContext.Response.StatusCode;
// Assert
Assert.IsTrue(result, "Invoker Result");
Assert.AreEqual(401, statusCode, "Status Code");
mocks.VerifyAll();
}
Although, thats not very useful without this helper function:
public static HttpContextBase FakeHttpContext(MockRepository mocks, bool isAuthenticated)
{
var context = mocks.StrictMock<HttpContextBase>();
var request = mocks.StrictMock<HttpRequestBase>();
var response = mocks.StrictMock<HttpResponseBase>();
var session = mocks.StrictMock<HttpSessionStateBase>();
var server = mocks.StrictMock<HttpServerUtilityBase>();
var cachePolicy = mocks.Stub<HttpCachePolicyBase>();
var user = mocks.StrictMock<IPrincipal>();
var identity = mocks.StrictMock<IIdentity>();
var itemDictionary = new Dictionary<object, object>();
identity.Expect(id => id.IsAuthenticated).Return(isAuthenticated);
user.Expect(u => u.Identity).Return(identity).Repeat.Any();
context.Expect(c => c.User).PropertyBehavior();
context.User = user;
context.Expect(ctx => ctx.Items).Return(itemDictionary).Repeat.Any();
context.Expect(ctx => ctx.Request).Return(request).Repeat.Any();
context.Expect(ctx => ctx.Response).Return(response).Repeat.Any();
context.Expect(ctx => ctx.Session).Return(session).Repeat.Any();
context.Expect(ctx => ctx.Server).Return(server).Repeat.Any();
response.Expect(r => r.Cache).Return(cachePolicy).Repeat.Any();
response.Expect(r => r.StatusCode).PropertyBehavior();
return context;
}
So that gets you confirmation that users not in a role don't have access. I tried writing a test to confirm the opposite, but after two more hours of digging through mvc plumbing I will leave it to manual testers. (I bailed when I got to the VirtualPathProviderViewEngine class. WTF? I don't want anything to do a VirtualPath or a Provider or ViewEngine much the union of the three!)
I am curious as to why this is so hard in an allegedly "testable" framework.
Why not just use reflection to look for the [Authorize] attribute on the controller class and / or the action method you are testing? Assuming the framework does make sure the Attribute is honored, this would be the easiest thing to do.
I don't agree with Dylan's answer, because 'user must be logged in' does not imply that 'controller method is annotated with AuthorizeAttribute'
to ensure 'user must be logged in' when you call the action method, the ASP.NET MVC framework does something like this (just hold on, it will get simpler eventually)
let $filters = All associated filter attributes which implement
IAuthorizationFilter
let $invoker = instance of type ControllerActionInvoker
let $ctrlCtx = instance or mock of type ControllerContext
let $actionDesc = instance or mock of type ActionDescriptor
let $authzCtx = $invoker.InvokeAuthorizationFilters($ctrlCtx, $filters, $actionDesc);
then controller action is authorized when $authzCtx.Result is not null
It is hard to implement this pseudo script in a working c# code. Likely, Xania.AspNet.Simulator makes it really simple to setup a test like this and performs exactly these step under the cover. here is an example.
first install the package from nuget (version 1.4.0-beta4 at the time of writing)
PM > install-package Xania.AspNet.Simulator -Pre
Then your test method could look like this (assuming NUnit and FluentAssertions are installed):
[Test]
public void AnonymousUserIsNotAuthorized()
{
// arrange
var action = new ProfileController().Action(c => c.Index());
// act
var result = action.GetAuthorizationResult();
// assert
result.Should().NotBeNull();
}
[Test]
public void LoggedInUserIsAuthorized()
{
// arrange
var action = new ProfileController().Action(c => c.Index())
// simulate authenticated user
.Authenticate("user1", new []{"role1"});
// act
var result = action.GetAuthorizationResult();
// assert
result.Should().BeNull();
}
For .NET Framework we use this class to verify that every MVC and API Controller have AuthorizeAttribute and that every API Controller should have a RoutePrefixAttribute.
[TestFixture]
public class TestControllerHasAuthorizeRole
{
private static IEnumerable<Type> GetChildTypes<T>()
{
var types = typeof(Startup).Assembly.GetTypes();
return types.Where(t => t.IsSubclassOf(typeof(T)) && !t.IsAbstract);
}
[Test]
public void MvcControllersShouldHaveAuthrorizeAttribute()
{
var controllers = GetChildTypes<Controller>();
foreach (var controller in controllers)
{
var authorizeAttribute = Attribute.GetCustomAttribute(controller, typeof(System.Web.Mvc.AuthorizeAttribute), true) as System.Web.Mvc.AuthorizeAttribute;
Assert.IsNotNull(authorizeAttribute, $"MVC-controller {controller.FullName} does not implement AuthorizeAttribute");
}
}
[Test]
public void ApiControllersShouldHaveAuthorizeAttribute()
{
var controllers = GetChildTypes<ApiController>();
foreach (var controller in controllers)
{
var attribute = Attribute.GetCustomAttribute(controller, typeof(System.Web.Http.AuthorizeAttribute), true) as System.Web.Http.AuthorizeAttribute;
Assert.IsNotNull(attribute, $"API-controller {controller.FullName} does not implement AuthorizeAttribute");
}
}
[Test]
public void ApiControllersShouldHaveRoutePrefixAttribute()
{
var controllers = GetChildTypes<ApiController>();
foreach (var controller in controllers)
{
var attribute = Attribute.GetCustomAttribute(controller, typeof(System.Web.Http.RoutePrefixAttribute), true) as System.Web.Http.RoutePrefixAttribute;
Assert.IsNotNull(attribute, $"API-controller {controller.FullName} does not implement RoutePrefixAttribute");
Assert.IsTrue(attribute.Prefix.StartsWith("api/", StringComparison.OrdinalIgnoreCase), $"API-controller {controller.FullName} does not have a route prefix that starts with api/");
}
}
}
It is a bit easier in .NET Core and .NET 5<. Here a MVC Controller inherits from Controller that in turn inherits from ControllerBase. An Api Controller inherits directly from ControllerBase and therefore we can test MVC and API Controllers using a single method:
public class AuthorizeAttributeTest
{
private static IEnumerable<Type> GetChildTypes<T>()
{
var types = typeof(Startup).Assembly.GetTypes();
return types.Where(t => t.IsSubclassOf(typeof(T)) && !t.IsAbstract);
}
[Fact]
public void ApiAndMVCControllersShouldHaveAuthorizeAttribute()
{
var controllers = GetChildTypes<ControllerBase>();
foreach (var controller in controllers)
{
var attribute = Attribute.GetCustomAttribute(controller, typeof(Microsoft.AspNetCore.Authorization.AuthorizeAttribute), true) as Microsoft.AspNetCore.Authorization.AuthorizeAttribute;
Assert.NotNull(attribute);
}
}
}

Unit Testing a controller that uses windows authentication

-------Please see updates below as I now have this set up for dependency injection and the use of the MOQ mocking framework. I'd still like to split up my repository so it doesn't directly depend on pulling the windowsUser within the same function.
I have a Web API in an intranet site that populates a dropdown. The query behind the dropdown takes the windows username as a parameter to return the list.
I realize I don't have all of this set up correctly because I'm not able to unit test it. I need to know how this "should" be set up to allow unit testing and then what the unit tests should look like.
Additional info: this is an ASP.NET MVC 5 application.
INTERFACE
public interface ITestRepository
{
HttpResponseMessage DropDownList();
}
REPOSITORY
public class ExampleRepository : IExampleRepository
{
//Accessing the data through Entity Framework
private MyDatabaseEntities db = new MyDatabaseEntities();
public HttpResponseMessage DropDownList()
{
//Get the current windows user
string windowsUser = HttpContext.Current.User.Identity.Name;
//Pass the parameter to a procedure running a select query
var sourceQuery = (from p in db.spDropDownList(windowsUser)
select p).ToList();
string result = JsonConvert.SerializeObject(sourceQuery);
var response = new HttpResponseMessage();
response.Content = new StringContent(result, System.Text.Encoding.Unicode, "application/json");
return response;
}
}
CONTROLLER
public class ExampleController : ApiController
{
private IExampleRepository _exampleRepository;
public ExampleController()
{
_exampleRepository = new ExampleRepository();
}
[HttpGet]
public HttpResponseMessage DropDownList()
{
try
{
return _exampleRepository.DropDownList();
}
catch
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound));
}
}
}
UPDATE 1
I have updated my Controller based on BartoszKP's suggestion to show dependency injection.
UPDATED CONTROLLER
public class ExampleController : ApiController
{
private IExampleRepository _exampleRepository;
//Dependency Injection
public ExampleController(IExampleRepository exampleRepository)
{
_exampleRepository = exampleRepository;
}
[HttpGet]
public HttpResponseMessage DropDownList()
{
try
{
return _exampleRepository.DropDownList();
}
catch
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound));
}
}
}
UPDATE 2
I have decided to use MOQ as a mocking framework for unit testing. I'm able to test something simple, like the following. This would test a simple method that doesn't take any parameters and doesn't include the windowsUser part.
[TestMethod]
public void ExampleOfAnotherTest()
{
//Arrange
var mockRepository = new Mock<IExampleRepository>();
mockRepository
.Setup(x => x.DropDownList())
.Returns(new HttpResponseMessage(HttpStatusCode.OK));
ExampleController controller = new ExampleController(mockRepository.Object);
controller.Request = new HttpRequestMessage();
controller.Configuration = new HttpConfiguration();
//Act
var response = controller.DropDownList();
//Assert
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
}
I need help testing the DropDownList method (one that does include code to get the windowsUser). I need advice on how to break this method apart. I know both parts shouldn't been in the same method. I don't know how to arrange splitting out the windowsUser variable. I realize this really should be brought in as a parameter, but I can't figure out how.
You usually do not unit-test repositories (integration tests verify if they really persist the data in the database correctly) - see for example this article on MSDN:
Typically, it is difficult to unit test the repositories themselves, so it is often better to write integration tests for them.
So, let's focus on testing only the controller.
Change the controller to take IExampleRepository in its constructor as a parameter:
private IExampleRepository _exampleRepository;
public ExampleController(IExampleRepository exampleRepository)
{
_exampleRepository = exampleRepository;
}
Then, in your unit tests, use one of mocking frameworks (such as RhinoMock for example) to create a stub for the sole purpose of testing the controller.
[TestFixture]
public class ExampleTestFixture
{
private IExampleRepository CreateRepositoryStub(fake data)
{
var exampleRepositoryStub = ...; // create the stub with a mocking framework
// make the stub return given fake data
return exampleRepositoryStub;
}
[Test]
public void GivenX_WhenDropDownListIsRequested_ReturnsY()
{
// Arrange
var exampleRepositoryStub = CreateRepositoryStub(X);
var exampleController = new ExampleController(exampleRepositoryStub);
// Act
var result = exampleController.DropDownList();
// Assert
Assert.That(result, Is.Equal(Y));
}
}
This is just a quick&dirty example - CreateRepositoryStub method should be of course extracted to some test utility class. Perhaps it should return a fluent interface to make the test's Arrange section more readable on what is given. Something more like:
// Arrange
var exampleController
= GivenAController()
.WithFakeData(X);
(with better names that reflect your business logic of course).
In case of ASP.NET MVC, the framework needs to know how to construct the controller. Fortunately, ASP.NET supports the Dependency Injection paradigm and a parameterless constructor is not required when using MVC unity.
Also, note the comment by Richard Szalay:
You shouldn't use HttpContext.Current in WebApi - you can use base.User which comes from HttpRequestBase.User and is mockable. If you really want to continue using HttpContext.Current, take a look at Mock HttpContext.Current in Test Init Method
One trick that I find very useful when trying to make old code testable when said code is accessing some global static or other messy stuff that I can't easily just parameterize is to wrap access to the resource in a virtual method call. Then you can subclass your system under test and use that in the unit test instead.
Example, using a hard dependency in the System.Random class
public class Untestable
{
public int CalculateSomethingRandom()
{
return new Random().Next() + new Random().Next();
}
}
Now we replace var rng = new Random();
public class Untestable
{
public int CalculateSomethingRandom()
{
return GetRandomNumber() + GetRandomNumber();
}
protected virtual int GetRandomNumber()
{
return new Random().Next();
}
}
Now we can create a testable version of the class:
public class Testable : Untestable
{
protected override int GetRandomNumber()
{
// You can return whatever you want for your test here,
// it depends on what type of behaviour you are faking.
// You can easily inject values here via a constructor or
// some public field in the subclass. You can also add
// counters for times method was called, save the args etc.
return 4;
}
}
The drawback with this method is that you can't use (most) isolation frameworks to implement protected methods (easily), and for good reason, since protected methods are sort of internal and shouldn't be all that important to your unit tests. It's still a really handy way of getting things covered with tests so you can refactor them, instead of having to spend 10 hours without tests, trying to do major architectual changes to your code before you get to "safety".
Just another tool to keep in mind, I find it comes in handy from time to time!
EDIT: More concretely, in your case you might want to create a protected virtual string GetLoggedInUserName(). This will technically speaking keep the actual call to HttpContext.Current.User.Identity.Name untested, but you will have isolated it to the simplest smallest possible method, so you can test that the code is calling the correct method the right amount of times with the correct args, and then you simply have to know that HttpContext.Current.User.Identity.Name contains what you want. This can later be refactored into some sort of user manager or logged in user provider, you'll see what suits best as you go along.

MVC4 / Mocking Controller.Request

I´m currently working on a MVC4 Project. As I did a few refactorings the tests should be changed too.
In the first scenario a session hash had to be passed included within the URL. That being nasted, I decided to pass it to the server as a Request header.
Example:
[HttpPost]
public ActionResult Generate(ClipGenerateRequest request)
{
string hash = Request.Headers["hash"];
ClipGenerationResponse responseModel = new ClipGenerationResponse();
return Json(responseModel, JsonRequestBehavior.AllowGet);
}
The problem now seems to be that I'm unable to mock the Request object to a custom one as the Request object is a read-only object. Dynamically setting the header doesn't work, as the Request is null when performing Unit Tests. So the following won't work:
[TestMethod]
public void GenerateTest()
{
GenerationController target = new GenerationController(this.loginModelMock, this.clipTemplateModelMock, this.clipTemplateFieldModelMock);
target.Request = this.requestBase;
string templateId = "0";
ActionResult actual = target.Generate(templateId);
Assert.AreEqual(typeof(JsonResult), actual.GetType());
Assert.AreEqual(typeof(ClipGenerationResponse), ((JsonResult)actual).Data.GetType());
}
Where this.requestBase would be mock created with Moq.
public HttpContextBase CreateMockHttpContext()
{
var serverVariables = new NameValueCollection {
{ "UserHostAddress", "127.0.0.1" },
{ "UserAgent", "Unit Test Value" }
};
var httpRequest = new Moq.Mock<HttpRequestBase>();
httpRequest.SetupGet(x => x.Headers).Returns(
new System.Net.WebHeaderCollection {
{"hash", "somehash"}
}
);
httpRequest.Setup(x => x.ServerVariables.Get(It.IsAny<string>()))
.Returns<string>(x =>
{
return serverVariables[x];
});
var httpContext = (new Moq.Mock<HttpContextBase>());
httpContext.Setup(x => x.Request).Returns(httpRequest.Object);
return httpContext.Object;
}
Nor the static way would work:
target.Request.Headers["hash"] = "hash";
So, I'm wondering how this could be fixed nicely. I could always obtain the Request in the Constructor, set a class variable to hold the Request, and then mock the getter / setter for testing purposes, but I'd rather use a nicer way to do it. Though I don't seem to know a way to get it working.
PS: Please note that some class names may have been altered for preview.
Update
As you seem to be unable to mock HttpContext.Current.Request, I decided to mock the HttpContext.Current. Resulting in:
container.RegisterInstance<HttpRequest>(HttpContext.Current.Request);
Sadly this works for the API, but not for unit testing as HttpContext cannot e mocked as it's not an interface.
Initialization method
SomeApiTest.Controllers.LoginControllerTest.Initialize
threw exception. System.NotSupportedException:
System.NotSupportedException: Type to mock must be an interface or an
abstract or non-sealed class. .
The suggested way was by doing:
container.RegisterInstance<HttpRequestBase>(HttpContext.Current.Request);
But this doesn't work because Request cannot be cast to HttpRequestBase.
Which means, I do now have a way to unit test my code, but it will no longer be able to run..
Testing if this problem could be solved using a HttpRequestWrapper.
Looks like the following does work for testing:
HttpRequestBase requestBase = new HttpRequestWrapper(HttpContext.Current.Request);
container.RegisterInstance<HttpRequestBase>(requestBase);
But not for runtime. Because:
- Additional headers are not sent, such as: UserHostAddress, Custom Headers
with Postman is set with every request a custom header, named "hash". Using this method, it looks like these headers are no longer set.
Looks like headers are set when the method is called, but not when the Controller itself is created. Therefore Dependency Injection on this might not be suitable.
Ugly Temporary fix:
private AuthenticationHelper authenticationHelper = null;
private ILoginModel iLoginModel = null;
private IModuleModel iModuleModel = null;
private HttpRequestBase iRequestBase = null;
public LoginController(ILoginModel loginModel, IModuleModel moduleModel, HttpRequestBase requestBase)
{
this.authenticationHelper = new AuthenticationHelper(loginModel);
this.iLoginModel = loginModel;
this.iModuleModel = moduleModel;
this.iRequestBase = requestBase;
}
private HttpRequestBase GetRequestBase()
{
if (Request != null)
{
return Request;
}
else
{
return iRequestBase;
}
}
[HttpPost]
public ActionResult Login(LoginRequest login)
{
var ip = this.authenticationHelper.GetIpAddress(GetRequestBase());
var userAgent = this.authenticationHelper.GetUserAgent(GetRequestBase());
}
When within Controller you refer to something by static classes or Controller properties you usually shoot yourself in the boot, because you make your class not testable with unit test, as in your case. To avoid such situation is that your Controller gets HttpRequestBase injected with IoC. For instance with Autofac after you register module AutofacWebTypesModule your Controllers may accept in their constructor parameter of type HttpRequestBase with basically what you get with Register property. So you should make your controller look like this:
public class GenerationController : Controller
{
readonly HttpRequestBase _request;
public GenerationController(
HttpRequestBase request,
// Additional constructor parameters goes here
)
{
_request = request;
}
}
With Unity you should register factory for HttpRequestBase like this:
container
.RegisterType<HttpRequestBase>(
new InjectionFactory(c => new HttpRequestWrapper(HttpContext.Current.Request))
);
When you create your Controller within unit test it is extremely easy to mock HttpRequestBase as all its properties, along with Headers are virtual.
This is approach I usually use in my projects. However there is option to mock Controller Request property even without rewriting your original code. It involves use of Controller ControllerContext property:
Mock<HttpContextBase> httpContextMock = new Mock<HttpContextBase>();
Mock<HttpRequestBase> httpReguestMock = new Mock<HttpRequestBase>();
httpContextMock.SetupGet(c => c.Request).Returns(httpReguestMock.Object);
GenerationController controller = new GenerationController();
controller.ControllerContext = new ControllerContext(httpContextMock.Object, new RouteData(), controller);
controller.Index();
My mock for request looks:
var request = A.Fake<HttpRequestBase>();
var formCollection = new NameValueCollection();
A.CallTo(() => request.HttpMethod).Returns("POST");
A.CallTo(() => request.Headers).Returns(new System.Net.WebHeaderCollection
{
{"X-Requested-With", "XMLHttpRequest"}
});
A.CallTo(() => request.Form).Returns(formCollection);
A.CallTo(() => request.ApplicationPath).Returns("/");
For my needs it works. I'am using FakeItEasy to mock request, but I'm pretty sure that you can use Moq instead. I'm using FakeItEasy and Moq parallel in my project, and it works perfect.

Mocking a MembershipUser

I'm currently developing an asp.net mvc 2 application which uses the default SqlMembershipProvider for authentication. I've implemented a controller method that reads the ProviderUserKey of the current user by calling Membership.GetUser().ProviderUserKey.
Now I'm trying to write some test methods for this controller.
To get rid of the dependancy on the static Membership class, I've created a thin wrapper and made my controller depend on the corresponding interface:
public interface IStaticMembershipService {
MembershipUser GetUser();
void UpdateUser(MembershipUser user);
}
So far everything works, but in order to unit-test the controller, I still need to mock the GetUser() method of this interface and return a MembershipUser object that contains a ProviderUserKey property. What is the easiest way to mock such an object?
I'm using moq as mocking framework.
It'd look something like this:
var membershipMock = new Mock<IStaticMembershipService>();
var userMock = new Mock<MembershipUser>();
userMock.Setup(u => u.ProviderUserKey).Returns(guid);
membershipMock.Setup(s => s.GetUser()).Returns(userMock.Object);
If the MembershipUser class doesn't lend itself to mocking (i.e. if ProviderUserKey isn't virtual), you'll want to create your own object to represent the values you're going to need from a MembershipUser object, and have your service return one of those instead.
There's also a slight possibility that a MembershipUser is a poco-like object, and you can create an instance like this:
var userMock = new MembershipUser {ProviderUserKey = guid};
I think you need to separate your implementation specifics from the interface the consumer really cares about. I'm not sure what your control needs the ProviderUserKey for, if it's casting it to a specific class, etc., but I would look at making your interface actually meet the controller's needs, not the other way around. Something like (without knowing more details):
public interface IMembershipDetailsService {
Guid UserKey { get; }
}
Once you do that level of abstraction, then mocking becomes much easier, because you could just do:
membershipService.Setup (svc => svc.UserKey).Returns (myGuid);
Just another thought, rather than trying to return a whole MembershipUser object you need to further stub.
Something similar to this:
var user = new MembershipUser();
var membershipService = new Mock<IStaticMembershipService>();
membershipService.Setup(p => p.GetUser()).Returns(user);
Could you do something like below if you need to Mock out the HttpContext stuff too.. below is using NUnit and Moq.
[SetUp]
private void Setup()
{
_mockHttpContext = new Mock<HttpContextBase>();
_mockStaticMembership = new Mock<IStaticMembershipService>();
_mockUser = new Mock<MembershipUser>();
_mockPrincipalUser = new Mock<IPrincipal>();
_mockHttpContext.Setup(http => http.User).Returns( _mockPrincipalUser.Object );
_mockPrincipalUser.Setup(principal => principal.Identity.Name).Returns("myname");
_mockUser.Setup(user => user.ProviderUserKey).Returns( Guid.NewGuid() );
_mockStaticMembership.Setup(membership => membership.GetUser(It.IsAny<string>())).Returns( _mockUser.Object );
}
[Test]
public void Some_Test_For_My_Controller()
{
var controller = new MyController( _mockStaticMembership.Object );
controller.ControllerContext = new ControllerContext(_mockHttpContext.Object, new RouteData(), controller);
//Test your action and verify
}

Categories