代码之家  ›  专栏  ›  技术社区  ›  Ragesh

如何使此ASP.NET MVC控制器更易于测试?

  •  5
  • Ragesh  · 技术社区  · 16 年前

    我有一个控制器 OnActionExecuting 做了这样的事:

    protected override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        base.OnActionExecuting(filterContext);
        string tenantDomain = filterContext.RouteData.Values["tenantDomain"] as string;
        if (!string.IsNullOrWhiteSpace(tenantDomain))
        {
            using (var tx = BeginTransaction())
            {
                this.Tenant = repo.FindOne(t => t.Domain == tenantDomain);
            }
        }
    }
    

    Tenant

    if (Tenant == null)
    {
       // Do something
    }
    else
    {
       // Do something else
    }
    

    如何测试此代码?我需要做的是以某种方式设置租户属性,但我不能,因为:

    1. 这是受保护的财产,而且

    更改的可见性 租客 感觉不对。除了单元测试我的派生控制器,我还有什么选择?

    6 回复  |  直到 16 年前
        1
  •  0
  •   Koen    16 年前

    使用反射?

    类似的方法应该有效(未经测试):

      YourController.GetType()
        .GetProperty("Tenant", BindingFlags.NonPublic | BindingFlags.Instance)
        .SetValue(yourControllerInstance, null, theTestValue);
    
        2
  •  1
  •   driis    16 年前

    我会这样做:

    在测试项目中创建一个具体的类,该类继承自抽象控制器,并将租户作为公共属性公开。在测试项目中使用模拟或伪代码没有什么错(当然,只方便测试的伪代码永远不应该出现在生产项目中)。

    or in command-line form .

        3
  •  0
  •   Ryan    16 年前

    您可以在抽象基上创建一个方法,仅用于单元测试。您可以将其公开,也可以对其进行内部设置 [assembly: InternalsVisibleTo("Tests")] this .

    internal void SetTenant(Tenant testValue)
    {
        Tenant = testValue;
    }
    
        4
  •  0
  •   Dom Ribaut    16 年前


    您的需求:

    我要做的就是

    从你的实现来看,租户是由回购协议提供的

    this.Tenant = repo.FindOne(t => t.Domain == tenantDomain);

    你需要的是能够以某种方式注入你的回购,从“回购”这个名字听起来是一件好事。

    --

        5
  •  0
  •   Ryan    16 年前

    好的,在重读@driis答案之后,我认为有一个更明确的方法来做到这一点,但它需要在您的控制器工厂中使用DI(网上有很多这样做的例子。)

    public class TenantFinder : ITenantFinder
    {
        // todo DI for repo
    
        public Tenant Find(string tenantDomain)
        {
            if (string.IsNullOrWhiteSpace(tenantDomain))
            {
                return null;
            }
            using (var tx = BeginTransaction())
            {
                return repo.FindOne(t => t.Domain == tenantDomain);
            }
        }
    }
    

    然后我们可以将这个类注入到控制器中(讨厌的是把构造器参数放得到处都是!)所以在抽象控制器中:

    protected override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        base.OnActionExecuting(filterContext);
        string tenantDomain = filterContext.RouteData.Values["tenantDomain"] as string;
        Tenant = Finder.Find(tenantDomain );
    }
    

    然后在单元测试中,您可以创建 ITenantFinder NullTenantFinder 处理空的情况。

        6
  •  0
  •   vijaysylvester    16 年前

    有两种方法可以做到这一点

    1. (标准方式)

      Mock<TenantType> tenantMock = new Mock<TenantType>();    
      var controller = new TargetController();    
      Controller.Tenant = tenantMock.Object;
      
    2. 使用反射设置私有属性 (对于那些不熟悉模仿框架的人)

    例如。,

        private static void SetPrivateSetPropertyValue(Type type, object obj, string fieldName, object value)
        {
            PropertyInfo propInfo = type.GetProperty(fieldName);
            propInfo.SetValue(obj, value, null);
        }
    

    this.SetPrivateSetPropertyValue(TenantType.GetType(),controller , "Tenant",tenantInstance);
    

    谢谢,