【问题标题】:Skip a method execution to unit test controller flow [duplicate]跳过方法执行到单元测试控制器流程[重复]
【发布时间】:2016-03-03 22:02:29
【问题描述】:
public class DemoController : Controller
{


    private readonly ICommonOperationsRepository _commonRepo;

    public DemoController (ICommonOperationsRepository commonRepo)
    {
       _commonRepo = commonRepo;
    }
    public ActionResult Default()
    {
       var model = new DemoModel();
       try
       {
           **ConcreteClass cc = new ConcreteClass(Request.ServerVariables["HTTP_X_REWRITE_URL"].ToString());
            cc.ConcreteClassMethod();**

           model.ListTopListing.AddRange(_commonRepo.GetListings());
        }
        catch (Exception ex)
        {
            ExceptionHandler objErr = new ExceptionHandler(ex, "DemoController .Default()\n Exception : " + ex.Message);
            objErr.LogException();
         }
         return View(model);
     }

}

我正在尝试对我的控制器进行单元测试。 ConcreteClass 构造函数及其方法 ConcreteClassMethod 都对 HttpRequest 变量有一些依赖,我无法从我的单元测试中传递这些变量。

我想要一种方法,当我调用 DemoController 的默认操作时,我可以简单地跳过 ConcreteClass 的构造函数和 ConcreteClassMethod 的执行。

【问题讨论】:

  • 您不能创建对象的新实例并停止调用构造函数。您必须创建一个空的无参数构造函数。要么重新考虑你的方法的工作方式。您还可以使用依赖注入来注入值。
  • 不知道该怎么做。你能详细解释一下吗?
  • 请看我的回答,尤其是我刚刚添加的最后一点。如果您需要更多信息,请告诉我。
  • 请看修改。

标签: asp.net-mvc unit-testing dependency-injection nunit moq


【解决方案1】:

您不能创建对象的新实例并停止调用构造函数。您必须创建一个空的无参数构造函数。

public class ConcreteClass
{
    private string MyString;

    // Your constructor
    public ConcreteClass(string myString)
    {
        this.MyString = myString;
    }

    // Parameterless constructor
    public ConcreteClass()
    {
        // Do nothing, no code
    }

    // A method that might use MyString
    public void DoSomethingWithMyString()
    {
        var trimmedString = this.MyString.Trim();
    }
}

要么这样,要么重新考虑方法的工作方式,使其不依赖于在构造函数中传递字符串:

public class ConcreteClass
{        
    // No constructor required anymore

    // Pass the string in to the methods that need the string
    public void DoSomethingWithMyString(string myString)
    {
        var trimmedString = myString.Trim();
    }

    // Pass the string in to the methods that need the string
    public void DoSomethingElseWithMyString(string myString)
    {
        var trimmedString = Int32.Parse(myString);
    }
}

但是,这可能无法解决问题,请记住您想注入 Request 变量并且您无权访问它们,您不能只执行以下操作:

public class DemoController : Controller
{
    private string HttpRewriteUrl;

    public DemoController()
    {
        this.HttpRewriteUrl = Request.ServerVariables["HTTP_X_REWRITE_URL"].ToString();
    }

    // Custom constructor for unit testing
    public DemoController(string httpRewriteUrl)
    {
        this.HttpRewriteUrl = httpRewriteUrl;
    }

    public ActionResult Default()
    {
        // Get the value from the object
        ConcreteClass cc = new ConcreteClass(this.HttpRewriteUrl);
        cc.ConcreteClassMethod();
    }
}

现在在您的单元测试中,您可以使用第二个构造函数并将值传入:

var controller = new DemoController("your value to pass in here");
controller.Default();

【讨论】:

  • 问题是 cc.ConcreteClassMethod() 也访问了一些我想避免的请求变量。
  • 我建议以相同的方式将它们作为参数从您的控制器中传递出去。您会发现,如果您传入相应的值,它会让您更清楚地了解这些方法的作用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-05-15
  • 1970-01-01
  • 2015-02-27
  • 1970-01-01
相关资源
最近更新 更多