How to mock Controller.User using moq - c#

I have a couple of ActionMethods that queries the Controller.User for its role like this
bool isAdmin = User.IsInRole("admin");
acting conveniently on that condition.
I'm starting to make tests for these methods with code like this
[TestMethod]
public void HomeController_Index_Should_Return_Non_Null_ViewPage()
{
HomeController controller = new HomePostController();
ActionResult index = controller.Index();
Assert.IsNotNull(index);
}
and that Test Fails because Controller.User is not set.
Any idea?

You need to Mock the ControllerContext, HttpContextBase and finally IPrincipal to mock the user property on Controller. Using Moq (v2) something along the following lines should work.
[TestMethod]
public void HomeControllerReturnsIndexViewWhenUserIsAdmin() {
var homeController = new HomeController();
var userMock = new Mock<IPrincipal>();
userMock.Expect(p => p.IsInRole("admin")).Returns(true);
var contextMock = new Mock<HttpContextBase>();
contextMock.ExpectGet(ctx => ctx.User)
.Returns(userMock.Object);
var controllerContextMock = new Mock<ControllerContext>();
controllerContextMock.ExpectGet(con => con.HttpContext)
.Returns(contextMock.Object);
homeController.ControllerContext = controllerContextMock.Object;
var result = homeController.Index();
userMock.Verify(p => p.IsInRole("admin"));
Assert.AreEqual(((ViewResult)result).ViewName, "Index");
}
Testing the behaviour when the user isn't an admin is as simple as changing the expectation set on the userMock object to return false.

Using Moq version 3.1 (and NUnit):
[Test]
public void HomeController_Index_Should_Return_Non_Null_ViewPage()
{
// Assign:
var homeController = new HomeController();
Mock<ControllerContext> controllerContextMock = new Mock<ControllerContext>();
controllerContextMock.Setup(
x => x.HttpContext.User.IsInRole(It.Is<string>(s => s.Equals("admin")))
).Returns(true);
homeController.ControllerContext = controllerContextMock.Object;
// Act:
ActionResult index = homeController.Index();
// Assert:
Assert.IsNotNull(index);
// Place other asserts here...
controllerContextMock.Verify(
x => x.HttpContext.User.IsInRole(It.Is<string>(s => s.Equals("admin"))),
Times.Exactly(1),
"Must check if user is in role 'admin'");
}
Notice that there is no need to create mock for HttpContext, Moq supports nesting of properties when setting up the test.

When using AspNetCore I could not mock the ControllerContext since I got an exception.
Unsupported expression: m => m.HttpContext
Non-overridable members (here: ActionContext.get_HttpContext) may not be used in setup / verification expressions.
Instead I had to mock the HttpContext and create a ControllerContext and pass the HttpContext object along.
I did find that mocking claims or response/request objects works as well when using this method.
[Test]
public void TestSomeStuff() {
var name = "some name";
var httpContext = new Mock<HttpContext>();
httpContext.Setup(m => m.User.IsInRole("RoleName")).Returns(true);
httpContext.Setup(m => m.User.FindFirst(ClaimTypes.Name)).Returns(name);
var context = new ControllerContext(new ActionContext(httpContext.Object, new RouteData(), new ControllerActionDescriptor()));
var controller = new MyController()
{
ControllerContext = context
};
var result = controller.Index();
Assert.That(result, Is.Not.Null);
}

Related

How to unit test ViewComponent.Invoke()?

In ViewComponent object, HttpContext and User are read-only properties.
How to unit test such a component?
I'm using the MSTest Freamwork.
The follow properties are used in my code
Cookie
Session
User(System.Security.Principal)
public ViewViewComponentResult Invoke()
{
var vm = new SummaryViewModel();
if (User.Identity is ClaimsIdentity identity && identity.IsAuthenticated)
{
vm.IsAuthenticated = true;
vm.UserName = identity.Claims.FirstOrDefault(c => c.Type == "UserName").Value;
vm.PhotoUrl = identity.Claims.FirstOrDefault(c => c.Type == "FacePicture").Value;
}
return View(vm);
}
[TestMethod]
public void UserSummaryVcTest()
{
var component = new UserSummaryViewComponent();
var model = component.Invoke().ViewData.Model as SummaryViewModel;
Assert.AreEqual("UserName", model.UserName);
}
According to source code the ViewComponent relies on the ViewComponentContext.ViewContext to expose those read only properties, Which in turn accesses the HttpContext. That is your entry point to mock the desired values.
[TestMethod]
public void UserSummaryVcTest() {
// Arrange
var expected = "Username value";
var httpContext = new DefaultHttpContext(); //You can also Mock this
//...then set user and other required properties on the httpContext as needed
var viewContext = new ViewContext();
viewContext.HttpContext = httpContext;
var viewComponentContext = new ViewComponentContext();
viewComponentContext.ViewContext = viewContext;
var viewComponent = new UserSummaryViewComponent();
viewComponent.ViewComponentContext = viewComponentContext;
//Act
var model = viewComponent.Invoke().ViewData.Model as SummaryViewModel;
//Assert
Assert.AreEqual(expected, model.UserName);
}
Here is just a samle for async,
[TestMethod]
public async System.Threading.Tasks.Task InvokeAsyncNameAsync()
{
# setup mocks
...
var httpContext = new DefaultHttpContext();
var viewContext = new ViewContext();
viewContext.HttpContext = httpContext;
var viewComponentContext = new ViewComponentContext();
viewComponentContext.ViewContext = viewContext;
var footerComponent = CreateComponentInstance();
footerComponent.ViewComponentContext = viewComponentContext;
ViewViewComponentResult result = await footerComponent.InvokeAsync() as ViewViewComponentResult;
FooterModel resultModel = (FooterModel)result.ViewData.Model;
....
# do your asserts verifications
Assert.AreEqual(expectedTest, resultModel.FooterText);
}

Mocking IPrincipal in ASP.NET Core

I have an ASP.NET MVC Core application that I am writing unit tests for. One of the action methods uses User name for some functionality:
SettingsViewModel svm = _context.MySettings(User.Identity.Name);
which obviously fails in the unit test. I looked around and all suggestions are from .NET 4.5 to mock HttpContext. I am sure there is a better way to do that. I tried to inject IPrincipal, but it threw an error; and I even tried this (out of desperation, I suppose):
public IActionResult Index(IPrincipal principal = null) {
IPrincipal user = principal ?? User;
SettingsViewModel svm = _context.MySettings(user.Identity.Name);
return View(svm);
}
but this threw an error as well.
Couldn't find anything in the docs either...
The controller’s User is accessed through the HttpContext of the controller. The latter is stored within the ControllerContext.
The easiest way to set the user is by assigning a different HttpContext with a constructed user. We can use DefaultHttpContext for this purpose, that way we don’t have to mock everything. Then we just use that HttpContext within a controller context and pass that to the controller instance:
var user = new ClaimsPrincipal(new ClaimsIdentity(new Claim[]
{
new Claim(ClaimTypes.Name, "example name"),
new Claim(ClaimTypes.NameIdentifier, "1"),
new Claim("custom-claim", "example claim value"),
}, "mock"));
var controller = new SomeController(dependencies…);
controller.ControllerContext = new ControllerContext()
{
HttpContext = new DefaultHttpContext() { User = user }
};
When creating your own ClaimsIdentity, make sure to pass an explicit authenticationType to the constructor. This makes sure that IsAuthenticated will work correctly (in case you use that in your code to determine whether a user is authenticated).
In previous versions you could have set User directly on the controller, which made for some very easy unit tests.
If you look at the source code for ControllerBase you will notice that the User is extracted from HttpContext.
/// <summary>
/// Gets the <see cref="ClaimsPrincipal"/> for user associated with the executing action.
/// </summary>
public ClaimsPrincipal User => HttpContext?.User;
and the controller accesses the HttpContext via ControllerContext
/// <summary>
/// Gets the <see cref="Http.HttpContext"/> for the executing action.
/// </summary>
public HttpContext HttpContext => ControllerContext.HttpContext;
You will notice that these two are read only properties. The good news is that ControllerContext property allows for setting it's value so that will be your way in.
So the target is to get at that object. In Core HttpContext is abstract so it is a lot easier to mock.
Assuming a controller like
public class MyController : Controller {
IMyContext _context;
public MyController(IMyContext context) {
_context = context;
}
public IActionResult Index() {
SettingsViewModel svm = _context.MySettings(User.Identity.Name);
return View(svm);
}
//...other code removed for brevity
}
Using Moq, a test could look like this
public void Given_User_Index_Should_Return_ViewResult_With_Model() {
//Arrange
var username = "FakeUserName";
var identity = new GenericIdentity(username, "");
var mockPrincipal = new Mock<ClaimsPrincipal>();
mockPrincipal.Setup(x => x.Identity).Returns(identity);
mockPrincipal.Setup(x => x.IsInRole(It.IsAny<string>())).Returns(true);
var mockHttpContext = new Mock<HttpContext>();
mockHttpContext.Setup(m => m.User).Returns(mockPrincipal.Object);
var model = new SettingsViewModel() {
//...other code removed for brevity
};
var mockContext = new Mock<IMyContext>();
mockContext.Setup(m => m.MySettings(username)).Returns(model);
var controller = new MyController(mockContext.Object) {
ControllerContext = new ControllerContext {
HttpContext = mockHttpContext.Object
}
};
//Act
var viewResult = controller.Index() as ViewResult;
//Assert
Assert.IsNotNull(viewResult);
Assert.IsNotNull(viewResult.Model);
Assert.AreEqual(model, viewResult.Model);
}
There is also the possibility to use the existing classes, and mock only when needed.
var user = new Mock<ClaimsPrincipal>();
_controller.ControllerContext = new ControllerContext
{
HttpContext = new DefaultHttpContext
{
User = user.Object
}
};
In my case, I needed to make use of Request.HttpContext.User.Identity.IsAuthenticated, Request.HttpContext.User.Identity.Name and some business logic sitting outside of the controller. I was able to use a combination of Nkosi's, Calin's and Poke's answer for this:
var identity = new Mock<IIdentity>();
identity.SetupGet(i => i.IsAuthenticated).Returns(true);
identity.SetupGet(i => i.Name).Returns("FakeUserName");
var mockPrincipal = new Mock<ClaimsPrincipal>();
mockPrincipal.Setup(x => x.Identity).Returns(identity.Object);
var mockAuthHandler = new Mock<ICustomAuthorizationHandler>();
mockAuthHandler.Setup(x => x.CustomAuth(It.IsAny<ClaimsPrincipal>(), ...)).Returns(true).Verifiable();
var controller = new MyController(...);
var mockHttpContext = new Mock<HttpContext>();
mockHttpContext.Setup(m => m.User).Returns(mockPrincipal.Object);
controller.ControllerContext = new ControllerContext();
controller.ControllerContext.HttpContext = new DefaultHttpContext()
{
User = mockPrincipal.Object
};
var result = controller.Get() as OkObjectResult;
//Assert results
mockAuthHandler.Verify();
I want to hit my Controllers directly and just use DI like AutoFac. To do this I first registering ContextController.
var identity = new GenericIdentity("Test User");
var httpContext = new DefaultHttpContext()
{
User = new GenericPrincipal(identity, null)
};
var context = new ControllerContext { HttpContext = httpContext};
builder.RegisterInstance(context);
Next I enable property injection when I register the Controllers.
builder.RegisterAssemblyTypes(assembly)
.Where(t => t.Name.EndsWith("Controller")).PropertiesAutowired();
Then User.Identity.Name is populated, and I do not need to do anything special when calling a method on my Controller.
public async Task<ActionResult<IEnumerable<Employee>>> Get()
{
var requestedBy = User.Identity?.Name;
..................
I would look to implement an Abstract Factory Pattern.
Create an interface for a factory specifically for providing user names.
Then provide concrete classes, one which provides User.Identity.Name, and one that provides some other hard coded value that works for your tests.
You can then use the appropriate concrete class depending on production versus test code. Perhaps looking to pass the factory in as a parameter, or switching to the correct factory based on some configuration value.
interface IUserNameFactory
{
string BuildUserName();
}
class ProductionFactory : IUserNameFactory
{
public BuildUserName() { return User.Identity.Name; }
}
class MockFactory : IUserNameFactory
{
public BuildUserName() { return "James"; }
}
IUserNameFactory factory;
if(inProductionMode)
{
factory = new ProductionFactory();
}
else
{
factory = new MockFactory();
}
SettingsViewModel svm = _context.MySettings(factory.BuildUserName());
I got a brownfield .net 4.8 project that I needed to convert to .net 5.0 and I wanted to keep as much of the original code as possible, including the unit-/integration tests. The test for Controllers relied on the Context a lot so I created this Extension method to enable setting tokens, claims and headers:
public static void AddContextMock(
this ControllerBase controller,
IEnumerable<(string key, string value)> claims = null,
IEnumerable<(string key, string value)> tokens = null,
IEnumerable<(string key, string value)> headers = null)
{
HttpContext mockContext = new DefaultHttpContext();
if(claims != null)
{
mockContext.User = SetupClaims(claims);
}
if(tokens != null)
{
mockContext.RequestServices = SetupTokens(tokens);
}
if(headers != null)
{
SetupHeaders(mockContext, headers);
}
controller.ControllerContext = new ControllerContext()
{
HttpContext = mockContext
};
}
private static void SetupHeaders(HttpContext mockContext, IEnumerable<(string key, string value)> headers)
{
foreach(var header in headers)
{
mockContext.Request.Headers.Add(header.key, header.value);
}
}
private static ClaimsPrincipal SetupClaims(IEnumerable<(string key, string value)> claimValues)
{
var claims = claimValues.Select(c => new Claim(c.key, c.value));
return new ClaimsPrincipal(new ClaimsIdentity(claims, "mock"));
}
private static IServiceProvider SetupTokens(IEnumerable<(string key, string value)> tokenValues)
{
var mockServiceProvider = new Mock<IServiceProvider>();
var authenticationServiceMock = new Mock<IAuthenticationService>();
var authResult = AuthenticateResult.Success(
new AuthenticationTicket(new ClaimsPrincipal(), null));
var tokens = tokenValues.Select(t => new AuthenticationToken { Name = t.key, Value = t.value });
authResult.Properties.StoreTokens(tokens);
authenticationServiceMock
.Setup(x => x.AuthenticateAsync(It.IsAny<HttpContext>(), null))
.ReturnsAsync(authResult);
mockServiceProvider.Setup(_ => _.GetService(typeof(IAuthenticationService))).Returns(authenticationServiceMock.Object);
return mockServiceProvider.Object;
}
This uses Moq but can be adapted to other mocking frameworks. The authentication type is hardcoded to "mock" since I rely on default authentication but this could be supplied as well.
It is used as such:
_controllerUnderTest.AddContextMock(
claims: new[]
{
(ClaimTypes.Name, "UserName"),
(ClaimTypes.MobilePhone, "1234"),
},
tokens: new[]
{
("access_token", "accessTokenValue")
},
headers: new[]
{
("header", "headerValue")
});
If you're using Razor pages and want to override the claims:
[SetUp]
public void Setup()
{
var user = new ClaimsPrincipal(new ClaimsIdentity(
new Claim[] {
new("dateofbirth", "2000-10-10"),
new("surname", "Smith") },
"mock"));
_razorModel = new RazorModel()
{
PageContext = new PageContext
{
HttpContext = new DefaultHttpContext() { User = user }
}
};
}

ASP MVC Unit Testing GetUserId()

I have a controller, where I'm calling a userId:
var userId = User.Identity.GetUserId();
This makes my unit test fail, since User is null.
I've tried to set a user in the test method using this method, but User is still null in the controller when the test runs.
var context = new Mock<HttpContextBase>();
var mockIdentity = new Mock<IIdentity>();
context.SetupGet(x => x.User.Identity).Returns(mockIdentity.Object);
mockIdentity.Setup(u => u.Name).Returns("test_userName");
Any hints as to what I'm doing wrong?
The HttpContextBase.User is of type IPrincipal and you have not mocked it. That's why it is returning null when you access it in tests. You can mock it as follows
var controllerContext = new Mock<ControllerContext>();
var principal = new Moq.Mock<IPrincipal>();
principal.Setup(p => p.IsInRole("Administrator")).Returns(true);
principal.SetupGet(x => x.Identity.Name).Returns(userName);
controllerContext.SetupGet(x => x.HttpContext.User).Returns(principal.Object);
controller.ControllerContext = controllerContext.Object;
Here is the reference of this code
Okay, so according to this post, you can do it like this:
public class MyController: Controller
{
public Func<string> GetUserId; //For testing
public MyController()
{
GetUserId = () => User.Identity.GetUserId();
}
//controller actions
}
And then instead of caling User.Identity.GetUserId() when you want the user, you just call GetUserId() and mock out the user id in your test:
controller = new MyController()
{
GetUserId = () => "IdOfYourChoosing"
};
You are mocking HttpContextBase but are not passing it to your controller.
Try this pattern:
Class:
public MyClass
{
private readonly HttpContextBase _contextBase;
public MyClass(HttpContextBase contextBase)
{
this._contextBase = contextBase;
}
public void Process()
{
var userId = _contextBase.User.Identity;
}
}
Test:
[Test]
public void MyClass_Test_SO()
{
// arrange
var context = new Mock<HttpContextBase>();
var mockIdentity = new Mock<IIdentity>();
context.SetupGet(x => x.User.Identity).Returns(mockIdentity.Object);
mockIdentity.Setup(u => u.Name).Returns("test_userName");
var sut = new MyClass(context.Object);
// act
sut.Process();
// assert
// ... whatever
}

Basic MVC3 UnitTest fails to UpdateModel()

It's been a while since I did any MVC work, so I'm hopefully missing something. I'm trying to write a test and controller action to simply Edit a DTO named "Business".
Controller Action:
[HttpPost]
public ActionResult Edit(string id, Business business)
{
try
{
var model = _businessRepository.Get(id);
if (model != null)
{
UpdateModel(model);
if (ModelState.IsValid)
{
_businessRepository.Save(model);
}
else
{
return View(business);
}
}
return RedirectToAction("Index");
}
catch
{
return View();
}
}
Test:
[TestMethod]
public void Edit_Post_Action_Updates_Model_And_Redirects()
{
// Arrange
var mockBusinessRepository = new Mock<IBusinessRepository>();
var model = new Business { Id = "1", Name = "Test" };
var expected = new Business { Id = "1", Name = "Not Test" };
// Set up result for business repository
mockBusinessRepository.Setup(m => m.Get(model.Id)).Returns(model);
mockBusinessRepository.Setup(m => m.Save(expected)).Returns(expected);
var businessController = new BusinessController(mockBusinessRepository.Object);
// Act
var result = businessController.Edit(model.Id, expected) as RedirectToRouteResult;
// Assert
Assert.IsNotNull(result);
Assert.AreEqual(result.RouteValues["action"], "Index");
mockBusinessRepository.VerifyAll();
}
The line that it is giving an exception on, is the UpdateModel() in the controller. The exception details are:
"Value cannot be null. Parameter name: controllerContext"
I have some code on Gist that I typically use to set up that ControllerContext. The code is a modified version that was originally taken from Hanselman's blog.
https://gist.github.com/1578697 (MvcMockHelpers.cs)
Setup the Controller context
The following is code snippet from a project which I work on, so maybe it's to much for you
public class TestBase
{
internal Mock<HttpContextBase> Context;
internal Mock<HttpRequestBase> Request;
internal Mock<HttpResponseBase> Response;
internal Mock<HttpSessionStateBase> Session;
internal Mock<HttpServerUtilityBase> Server;
internal GenericPrincipal User;
public void SetContext(Controller controller)
{
Context = new Mock<HttpContextBase>();
Request = new Mock<HttpRequestBase>();
Response = new Mock<HttpResponseBase>();
Session = new Mock<HttpSessionStateBase>();
Server = new Mock<HttpServerUtilityBase>();
User = new GenericPrincipal(new GenericIdentity("test"), new string[0]);
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);
Context.Setup(ctx => ctx.User).Returns(User);
Request.Setup(r => r.Cookies).Returns(new HttpCookieCollection());
Request.Setup(r => r.Form).Returns(new NameValueCollection());
Request.Setup(q => q.QueryString).Returns(new NameValueCollection());
Response.Setup(r => r.Cookies).Returns(new HttpCookieCollection());
var rctx = new RequestContext(Context.Object, new RouteData());
controller.ControllerContext = new ControllerContext(rctx, controller);
}
}
Then in your tests you can arrange:
//Arrange
SetContext(_controller);
Context.Setup(ctx => ctx.Request).Returns(Request.Object);
If you want to test your method with ModelState errors, add:
_controller.ModelState.AddModelError("Name", "ErrorMessage");
You need to mock the ControllerContext for your BusinessController.
See this question or this one.
I've managed to get what I wanted working by using Automapper instead of the UpdateModel.
I added in my automapper initialization (IPersistable is an interface for all my DTOs):
Mapper.CreateMap<IPersistable, IPersistable>().ForMember(dto => dto.Id, opt => opt.Ignore());
I then changed my controller action to:
[HttpPost]
public ActionResult Edit(string id, Business business)
{
try
{
var model = _businessRepository.Get(id);
if (model != null)
{
Mapper.Map(business, model);
if (ModelState.IsValid)
{
_businessRepository.Save(model);
}
else
{
return View(business);
}
}
return RedirectToAction("Index");
}
catch
{
return View();
}
}
And changed my test to:
[TestMethod]
public void Edit_Post_Action_Updates_Model_And_Redirects()
{
// Arrange
var mockBusinessRepository = new Mock<IBusinessRepository>();
var fromDB = new Business { Id = "1", Name = "Test" };
var expected = new Business { Id = "1", Name = "Not Test" };
// Set up result for business repository
mockBusinessRepository.Setup(m => m.Get(fromDB.Id)).Returns(fromDB);
mockBusinessRepository.Setup(m => m.Save(It.IsAny<Business>())).Returns(expected);
var businessController = new BusinessController(mockBusinessRepository.Object) {ControllerContext = new ControllerContext()};
//Act
var result = businessController.Edit(fromDB.Id, expected) as RedirectToRouteResult;
// Assert
Assert.IsNotNull(result);
Assert.AreEqual(result.RouteValues["action"], "Index");
mockBusinessRepository.VerifyAll();
}
I had the same problem and used the stack trace to pin this down to the ValueProvider. Building on Andrew's answer above for mocking some of the underlying objects used by a controller, I managed to solve the null value exception by also mocking the ValueProvider like this:
var controller = new MyController();
// ... Other code to mock objects used by controller ...
var mockValueProvider = new Mock<IValueProvider>();
controller.ValueProvider = mockValueProvider.Object;
// ... rest of unit test code which relies on UpdateModel(...)

Moq controller tests with repeated setup

I am getting started on the Moq framework and absolutely love it. I am writing some controller tests that have several services and interfaces to Arrange my controller for the test. I'd love to modularize it a bit more, and thought this would be a trivial task, but it turns out to be a bit trickier than I thought.
Here is one simple unit test that I have to show an example:
[Test]
public void Get_SignIn_Should_Return_View()
{
#region //TODO: figure out how to extract this out to avoid duplicate code
// Arrange
var membershipService = new Mock<IMembershipService>();
var formsService = new Mock<IFormsAuthenticationService>();
var userService = new Mock<IUserService>();
var dictService = new Mock<IDictionaryService>();
var shoppingBasketService = new Mock<IShoppingBasketService>();
//Create the service provider mock and pass in the IRepositoryFactory so that it isn't instantiating real repositories
var repoFactory = new Mock<IRepositoryFactory>();
var serviceProvider = new Mock<ServiceProvider>( (IRepositoryFactory)repoFactory.Object );
var context = new Mock<HttpContextBase> { DefaultValue = DefaultValue.Mock };
var sessionVars = new Mock<SessionVars>();
AccountController controller = new AccountController( serviceProvider.Object, sessionVars.Object )
{
FormsService = formsService.Object,
MembershipService = membershipService.Object,
UserService = userService.Object,
DictionaryService = dictService.Object,
ShoppingService = shoppingBasketService.Object
};
controller.ControllerContext = new ControllerContext()
{
Controller = controller,
RequestContext = new RequestContext( context.Object, new RouteData() )
};
#endregion
// Act
ActionResult result = controller.SignIn();
// Assert
Assert.IsInstanceOf<ViewResult>( result );
}
What I'd like to be able to do is take everything in the #region and extract that out into a helper method or [Setup] method, but if I do that, then I don't have access to each mock service to setup expectations.
Is there something I'm missing here, or do I really have to copy-and-paste this chunk of Arrange code in each Unit test?
Try using a context to setup all your mocks, then use test fixtures that inherit your context. Put the tests inside these fixtures and violà! This code might not be exactly right for the framework you are using. If it is NUnit then it will be. But the theory is there.
public abstract class MembershipTestContext
{
var membershipService = new Mock<IMembershipService>();
var formsService = new Mock<IFormsAuthenticationService>();
var userService = new Mock<IUserService>();
var dictService = new Mock<IDictionaryService>();
var shoppingBasketService = new Mock<IShoppingBasketService>();
//Create the service provider mock and pass in the IRepositoryFactory so that it isn't instantiating real repositories
var repoFactory = new Mock<IRepositoryFactory>();
var serviceProvider = new Mock<ServiceProvider>( (IRepositoryFactory)repoFactory.Object );
var context = new Mock<HttpContextBase> { DefaultValue = DefaultValue.Mock };
var sessionVars = new Mock<SessionVars>();
[SetUp]
AccountController controller = new AccountController( serviceProvider.Object, sessionVars.Object )
{
FormsService = formsService.Object,
MembershipService = membershipService.Object,
UserService = userService.Object,
DictionaryService = dictService.Object,
ShoppingService = shoppingBasketService.Object
};
controller.ControllerContext = new ControllerContext()
{
Controller = controller,
RequestContext = new RequestContext( context.Object, new RouteData() )
};
}
[TestFixture]
public class when_getting_sign_in : MembershipContext
{
[Test]
public void Should_return_view()
{
// Act
ActionResult result = controller.SignIn();
// Assert
Assert.IsInstanceOf<ViewResult>(result);
}
[Test]
public void Should_do_another_test()
{
... another test etc
}
}
One thing you could do is use the Mock.Get method (http://api.moq.me/html/C6B12927.htm) to retrieve the mock for a given object instance.
Another option would be to refactor your code and store references to your mock objects in instance variables of your test class (if all of the tests in the test class require them) or perhaps a simple data structure (if only some of the tests will require them).

Categories