As far as I see, unless my mvc4 app uses windows authentication (and so my controllers tries to read the User objects) when I create my controller instance from a TestMethod, the User object remains null. So my tests fails. What can I do to get them work?
Additional informations: This is my test:
[TestMethod]
public void Create()
{
var ctrl = new LanguageController();
var res = ctrl.Manage() as ViewResult;
Assert.IsNotNull(res);
Assert.AreEqual(res.ViewName, "Create");
}
And my LanguageController has a base class:
public class LanguageController : MyController
{
Which has a constructor, inside it I try to discover the user rights by an external Right Manager.
public class MyController : Controller
{
protected Rights rm;
public MyController()
{
this.rm = RightManager.Discover(User.Identity);
}
Here in this constructor I see the User is null.
Okay, there are few issues with your Unit test and I will go through them as I explain why the User is null.
It is simply because you haven't provide a stubbed version of the User (IPrincipal) instance. So you need to find a way to inject that into your Controller. It is important you externalize as much dependencies in your Controller so it provides not a clean Controller to work with but also and importantly promote the testability.
What I would do inject the dependencies as below.
Your SUT (System Under Test)
public class MyController : Controller
{
protected Rights rm;
public MyController(IPrincipal user, IRightManager rightManager)
{
this.rm = rightManager.Discover(user.Identity);
}
}
public class LanguageController : MyController
{
public LanguageController(IPrincipal user, IRightManager rightManager)
: base(user, rightManager)
{
}
public ActionResult Manage()
{
return View("Manage");
}
}
This gives me the ability to inject a fake User and also a fake Right Manager.
So how would you get the real User, RightManager when you run the application at runtime?
You can inject the dependencies to the Controller during the Controller creation.
If you don't use a dependency injection framework (Ideally you should), you can still inject dependencies in a manual way. For example, creating property in your Controller and inject the real instance in the Controller, and during the Unit Testing time inject the fake instance etc. I won't go into detail as I'm deviating a bit - but you can find lot SO questions/web references in regards to this aspect.
Your Unit test Now you have a way to inject your dependencies you can easily inject them from your Unit test. You can either using an Isolation framework (AKA and Mock object framework) or you can inject them as the old school way - which is the Hand written mocks/fakes/stubs. I suggest using an Isolation framework. Creating manual fakes, introduces unnecessary code duplication and maintenance issue. Since I don't know which framework you prefer, I created few handwritten fakes/mocks/stubs.
public class FakeRightManager : IRightManager {
public Rights Discover(IIdentity identity) {
return new Rights();
}
}
public class MyFakeIdentity : IIdentity {
public string AuthenticationType {
get { throw new NotImplementedException(); }
}
public bool IsAuthenticated {
get { throw new NotImplementedException(); }
}
public string Name {
get { throw new NotImplementedException(); }
}
}
public class MyFakePrincipal : IPrincipal {
public IIdentity Identity {
get { return new MyFakeIdentity(); }
}
public bool IsInRole(string role) {
throw new NotImplementedException();
}
}
You Unit Test :
[TestMethod]
public void ManageAction_Execute_ReturnsViewNameManager()
{
var fakeUser = new MyFakePrincipal();
var fakeRightManager = new FakeRightManager();
var ctrl = new LanguageController(fakeUser, fakeRightManager);
var res = ctrl.Manage() as ViewResult;
Assert.AreEqual<string>(res.ViewName, "Manage");
}
In your test you check for Assert.IsNotNull(res); this not necessary as if the res is null your second assert going to fail anyway.
Also always give a very descriptive precise Unit Test name. Reflect what you exactly testing. It improves the test readability and maintainability.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With