3

据我所知,除非我的 mvc4 应用程序在我从 TestMethod 创建控制器实例时使用 Windows 身份验证(因此我的控制器尝试读取用户对象),否则用户对象将保持为空。所以我的测试失败了。我该怎么做才能让他们工作?

附加信息:这是我的测试:

[TestMethod]
public void Create()
{
   var ctrl = new LanguageController();
   var res = ctrl.Manage() as ViewResult;
   Assert.IsNotNull(res);
   Assert.AreEqual(res.ViewName, "Create");
}

我的 LanguageController 有一个基类:

public class LanguageController : MyController
{

其中有一个构造函数,在其中我尝试通过外部权限管理器发现用户权限。

public class MyController : Controller
  {
     protected Rights rm;
     public MyController()
     {
        this.rm = RightManager.Discover(User.Identity);
     }

在此构造函数中,我看到 User 为空。

4

1 回答 1

2

好的,您的单元测试几乎没有问题,当我解释为什么用户为空时,我将通过这些问题。

这仅仅是因为您没有提供用户 (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 您的第二个断言无论如何都会失败。

也总是给出一个描述性非常精确的单元测试名称。反映您确切测试的内容。它提高了测试的可读性和可维护性。

于 2013-10-29T10:19:02.077 回答