好的,您的单元测试几乎没有问题,当我解释为什么用户为空时,我将通过这些问题。
这仅仅是因为您没有提供用户 (IPrincipal) 实例的存根版本。所以你需要找到一种方法将它注入到你的控制器中。在 Controller 中外部化尽可能多的依赖项很重要,因此它提供的不是一个干净的 Controller 可以使用,而且重要的是提高了可测试性。
我会做如下注入依赖项。
您的 SUT(被测系统)
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");
}
}
这使我能够注入假用户和假权限管理器。
那么,当您在运行时运行应用程序时,您将如何获得真正的用户 RightManager 呢?
您可以在创建控制器期间将依赖项注入控制器。
如果你不使用依赖注入框架(理想情况下你应该这样做),你仍然可以手动注入依赖。例如,在控制器中创建属性并在控制器中注入真实实例,并在单元测试期间注入假实例等。我不会详细说明,因为我有点偏离 - 但你可以找到很多 SO关于这方面的问题/网络参考。
您的单元测试
现在您有了一种注入依赖项的方法,您可以轻松地从单元测试中注入它们。您可以使用隔离框架(AKA 和 Mock 对象框架),也可以将它们作为老派的方式注入 - 这是手写的模拟/伪造/存根。我建议使用隔离框架。创建人工伪造品,引入了不必要的代码重复和维护问题。因为我不知道你喜欢哪个框架,所以我创建了几个手写的 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();
}
}
你单元测试:
[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");
}
在您的测试中,您检查 Assert.IsNotNull(res); 这没有必要,因为如果 res 为 null 您的第二个断言无论如何都会失败。
也总是给出一个描述性非常精确的单元测试名称。反映您确切测试的内容。它提高了测试的可读性和可维护性。