繁体   English   中英

注入后在MVC控制器上使用的测试属性

[英]Testing property used on mvc controller after injection

public class MyUser: IIdentity, IMyUser{
   // ommited for abbrev.       
}

public interface IMyUser
{
    int Id { get; set; }
    int? CompanyId { get; set; }        
}

在MyController内部,我正在使用MyUser和其他用户来填充组合框

public ActionResult Details(int? subsidId = null, int? req = null)
 {
    ...
    MyUser user = this.User.GetInfo();
    var obj1 = ... // ommited on purpose for abbrev.    
    populateCombos(subsidId, user.CompanyId, req); 
 }

我在这行populateCombos上遇到异常,因为用户对象始终为null。 在同一个控制器中,我正在注入IMyUser实现的接口

[Inject]
public IMyUser MyUser { get; set; }

使用ninject正确绑定了此属性(就像我的应用中的其他属性一样)

kernel.Bind<IMyUser>().To<MyUser>().InRequestScope();

现在在测试项目上,我正在通过模拟请求的依赖项初始化控制器

[SetUp]
public void Setup()
{
   _controller = new MyController(){
       ... repositories....
       MyUser = MockMyUser()
   }
}

private IMyUser MockMyUser()
{
    var u = new Mock<IMyUser>();
    u.SetupGet(x => x.Id).Returns(1);      
    u.SetupGet(x => x.CompanyId).Returns(99);    

    return u.Object;
}

在内部测试方法中,我编写了简单的测试

[Test]
public void CanDoDetails()
{
   ViewResult res = this.controller.Details(1, 2) as ViewResult;  

   var model = result.Model as MyModel;            

   Assert.IsNotNull(model);
}

问题是:

为什么我得到这个依赖关系( MyUserMyControllernull ),因为它是正确的注射? 我做错了什么?

更新:

public static MyUser GetInfo(this IPrincipal principal)
        {
            if (principal != null)
            {
                return principal.Identity as MyUser;    
            }

            return null;
        }

更新2:基于Nkosi的答案,我进行了以下更改

public interface IMyUser : IIdentity { ... }

内部详细信息ActionMethod控制器

IMyUser user = this.User.GetInfo();

并在测试方法下

[SetUp]
public void Setup()
{
    var mockUser = MockMyUser();
     string[] roles = new[] { "Admin", "SuperUser" };
    _controller = new MyController()
    {
       ....
       MyUser = this.MockMyUser(),
       ControllerContext = new ControllerContext() {
          Controller = _controller,
          RequestContext = new RequestContext(new MockHttpContext(mockUser, roles), new RouteData())
       }
    }

}
 but I'm still getting `IMyUser user = this.User.GetInfo();` `this.User` is still null. 

ps我还更改了GetInfo以返回IMyUser而不是MyUser

那模拟控制器又如何呢?

Mock<MyController> mockController = new Mock<MyController>();
mockController.SetupGet(t => t.MyUser).Returns(MockMyUser());

然后您可以通过模拟控制器.Object访问控制器并尝试进行测试。

我的建议也将是使IMyUser继承IIdentity

public class MyUser: IMyUser {
   // ommited for abbrev.       
}

public interface IMyUser: IIdentity {
    int Id { get; set; }
    int? CompanyId { get; set; }        
}

如果您使用的是Controller.User { get; }则要使单元测试正常工作Controller.User { get; } Controller.User { get; }是为控制器创建模拟/伪造用户。 为了获得对User的访问权限(只读),您必须创建一个模拟HttpContext y 幸运的是,您仍然只希望访问该User

private class MockHttpContext : HttpContextBase {
    private readonly IPrincipal user;

    public MockHttpContext(IIdentity identity , string[] roles = null) {
        var principal = new GenericPrincipal(identity, roles ?? new string[] { });
        user = principal;
    }

    public override IPrincipal User {
        get {
            return user;
        }
        set {
            base.User = value;
        }
    }
}

您可以设置主体以适合您的身份验证设置,以及在运行时提出的声明。 这只是一个例子。

[SetUp]
public void Setup()
{
   string[] roles = new[] { "Admin", "SuperUser" };
   var mockUser = MockMyUser();

   _controller = new MyController(){
       ... repositories....
       MyUser = mockUser
   };

   _controller.ControllerContext = new ControllerContext() {
        Controller = _controller,
        RequestContext = new RequestContext(new MockHttpContext(mockUser, roles), new RouteData())
    };

}

private IMyUser MockMyUser()
{
    var u = new Mock<IMyUser>();
    u.Setup(x => x.Name).Returns("username@test.io");
    u.Setup(x => x.Id).Returns(1);
    u.Setup(x => x.CompanyId).Returns(99);

    return u.Object;
}

现在应该允许

public static IMyUser GetInfo(this IPrincipal principal) {
    if (principal != null) {
        return principal.Identity as IMyUser;    
    }
    return null;
}

principal.Identity as IMyUser返回principal.Identity as IMyUser不为空。

更新

我使用上面提供的内容重新创建了测试的最低版本,并且能够测试并通过。

[TestClass]
public class MyUserDependentControllerTest {

    [TestMethod]
    public void CanDoDetails() {
        //Arrange
        string[] roles = new[] { "Admin", "SuperUser" };

        var u = new Mock<IMyUser>();
        u.Setup(x => x.Name).Returns("username@test.io");
        u.Setup(x => x.Id).Returns(1);
        u.Setup(x => x.CompanyId).Returns(99).Verifiable();

        var mockUser = u.Object;

        var controller = new MyController() {
            //... repositories....
            MyUser = mockUser
        };

        controller.ControllerContext = new ControllerContext() {
            Controller = controller,
            RequestContext = new RequestContext(new MockHttpContext(mockUser, roles), new RouteData())
        };

        //Act
        var result = controller.Details(1, 2);

        //Assert
        var viewResult = result as ViewResult;
        Assert.IsNotNull(viewResult);

        var model = viewResult.Model as MyModel;
        Assert.IsNotNull(model);

        u.Verify();
    }

    public class MyController : Controller {
        public ActionResult Details(int? subsidId = null, int? req = null) {
            //...
            var user = this.User.GetInfo();
            //
            populateCombos(subsidId, user.CompanyId, req);

            //this is just for matching test expectations
            var model = new MyModel();
            return View(model);
        }

        private void populateCombos(int? subsidId, int? nullable, int? req) {
            //Empty as I have no clue what happens in here
        }

        public IMyUser MyUser { get; set; }
    }

    public class MyModel { }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM