【问题标题】:C# Pass controller method name dynamically and execute itC#动态传递控制器方法名称并执行它
【发布时间】:2021-09-13 16:43:15
【问题描述】:

我为我的控制器方法编写了单元测试代码,它涵盖了所有块。

这是有问题的相关行。

[TestMethod()]

public void ManageAreasTest()
{
    //bunch of code
    var result = new AdminController().ManageAreas();
    //more code
}

这 ManageAreas() 行几乎是其他单元测试代码逻辑中唯一会改变的东西(例如,ManageSubAreas() 控制器方法,它与 ManageAreas() 具有完全相同的逻辑,只是返回不同的视图)。

所以,为了避免单元测试代码的复制粘贴,只是改变方法调用,我想动态传递控制器方法名并执行它。

为此,我创建了一个新类

public partial class ExecuteControllerMethodTest
{
    public string ActionName { get; set; }
    public string ControllerName { get; set; }
}

我知道的唯一方法是 RedirectToAction,所以我在我的单元测试类中创建了一个方法

private RedirectToRouteResult ExecuteControllerMethod(ExecuteControllerMethodTest model)
{
    return RedirectToAction(model.ActionName, model.ControllerName);
}

在我的单元测试代码中,我像这样更新了它

[TestMethod()]
    
    public void ManageAreasTest()
    {
        ExecuteControllerMethodTest model = new ExecuteControllerMethodTest();
        model.ControllerName = "Admin";
        model.ActionName = "ManageAreas";
        //bunch of code
        var result = ExecuteControllerMethod(model);
        //more code
    }

但是,当我调试代码时,我在 ManageAreas() 中的断点没有被命中。

总的来说,这是我的问题:

  • 我是否使用正确的方法来实现该目标?

  • 如果是这样,我做错了什么?

非常感谢您!

编辑:

我的计划是创建一个额外的方法,该方法将包含来自 ManageAreasTest() 的几乎所有代码。此时 UT 方法唯一要做的就是初始化类变量并运行方法本身。

[TestMethod()]

public void ManageAreasTest()
{
    ExecuteControllerMethodTest model = new ExecuteControllerMethodTest();
    model.ControllerName = "Admin";
    model.ActionName = "ManageAreas";
    
    RunAdminControllerUnitTestForMethod(model);
}

private void RunAdminControllerUnitTestForMethod(model)
{
    //Pretty much the entire code from ManageAreasTest()
    //Just instead of var result = new AdminController().ManageAreas();
    //It will be
    var result = ExecuteControllerMethod(model);
}

我认为更好的问题是:除了调用控制器方法之外,还有哪些其他方法

var result = new AdminController().ManageAreas();

什么时候方法名是动态的? 比如,如果我想传递“ManageAreas”,它会像 new AdminController().ManageAreas() 一样执行这个方法。

【问题讨论】:

    标签: c# asp.net-mvc unit-testing


    【解决方案1】:

    通常,当您有一堆重复的代码时,通常的方法(在单元测试或生产代码中)是使用重复的代码提取一个(私有)方法,并且只重复调用。所以你原来的方法可以重构成这样的:

    [TestMethod()]
    public void ManageAreasTest()
    {
        //Setup part, just a sample idea
        var controller = this.BuildController();
    
        //Here goes the call itself, where you use the previously built controller and call the appropriate method each time
        var result = controller.ManageAreas();
    
        //Assert part, here goes the duplicated code too
        //Parameters will help separate each test case apart
        this.DoAsserts("ManageView");
    }
    

    然后我们在测试类中定义辅助方法:

    private AdminController BuildController()
    {
        //Setup any other environment you need
    
        //Create the controller
        var controller = new AdminController();
    
        //Here you configure and initialize the controller, inject dependencies and the like
    
        return controller;
    }
    
    private void DoAsserts(string viewName)
    {
        //Here go the bunch of assert and other post-action validations
        Assert.AreEqual(......);
        Assert.AreEqual(......);
        Assert.AreEqual(......);
    }
    

    当然,这只是一个小例子,但总体思路是这样。其他测试只是复制调用(一行)并更改被测方法和所需参数。

    【讨论】:

    • 那么,几乎只是将重复的部分存储到方法中,并且只有唯一的方法调用行吗?
    • 简而言之,是的。这样,唯一的重复就是调用,而不是全部。
    • 我更新了我的主题,如果它更清晰,请告诉我。
    【解决方案2】:

    我设法通过以下代码行实现了我的目标:

    AdminController adm = new AdminController();
    typeof(AdminController).GetMethod(model.ActionName).Invoke(adm,null);
    

    这样,我将方法名称作为字符串传递,一旦执行此代码,它就会直接进入有问题的控制器方法。

    【讨论】:

      猜你喜欢
      • 2014-09-05
      • 1970-01-01
      • 2023-04-09
      • 1970-01-01
      • 2017-01-13
      • 1970-01-01
      • 1970-01-01
      • 2015-09-10
      • 2013-10-08
      相关资源
      最近更新 更多