如何将模型值从测试 class 传递到控制器 class 中的操作方法

How to pass Model value from Test class to Action Method in Controller class

我正在为 MVC 应用程序创建一些 Nunit 测试。我正在为我的控制器 class 中的方法编写测试用例。我正在使用 Nsubstitute 模拟对象。

我正在学习 Nunit 和 Nsubstitue,但我不知道如何将在测试用例方法中模拟的模型值传递给我的控制器方法。

下面是我在控制器中的方法class:

public ActionResult Manage(string id)
{
    var clusterCollections = ReadXml();
    int clusterIndex = clusterCollections.ClusterCollectionList.FindIndex(a => a.ClusterId == id);
    var model = new ClusterManagementModel()
    {
        ClusterNodeDetailsList = BindClusterDetailsToGrid(id),
        DropDownListClusterName = BindClusterNameToDropDown(),
        CurrentClusterId = clusterIndex,
        CurrentClusterName = id,
        HStatus = Hstatus(id),
        IStatus = Istatus(id)
    };
    return View(model);
}

这是我写的测试用例:

[TestCase]
public void TestManage()
{         
    var ManagementController = Substitute.ForPartsOf<ClusterManagementController>();
    var ManagementModel = Substitute.ForPartsOf<ClusterManagementModel>();
    ClusterCollections clusterCollection = new ClusterCollections();
    List<ClusterNodeDetails> ClusterNodes = new List<ClusterNodeDetails>();
    List<DDL_ClusterName> DropDownListClusterName = new List<DDL_ClusterName>();
    ManagementController.ReadXml().Returns(clusterCollection);
    ManagementModel = new ClusterManagementModel()
    {
        ClusterNodeDetailsList = ClusterNodes,
        DropDownListClusterName = DropDownListClusterName,
        CurrentClusterId = 1,
        CurrentClusterName = "UnitTesting",
        HStatus = "True",
        IStatus = "Success"
    };
    var result = ManagementController.Manage("1") as ActionResult;
    Assert.AreEqual(ManagementModel, result);
}

如果我在测试用例方法中有错误,请指正。

如果我的TestCase有错,你能给我一个建议如何为上面的方法写一个TestCase吗(public ActionResult Manage(string id))

I don't know, how to pass Model value

简短的回答是,在当前形式下,您无法将在测试中创建的模型传递给控制器​​。这是人们 运行 第一次开始尝试对其代码进行单元测试时遇到的一个常见问题。摆脱困境的方法是在开始编写生产代码时考虑到测试。

一种常见的方法是从 class 中提取依赖项并通过 class 的构造函数注入这些依赖项。因此,您可以将模型创建逻辑提取到 ModelFactory 中并修改您的控制器以具有这样的构造函数:

public ManagementController(IModelFactory modelFactory) {
    _modelFactory = modelFactory;
}

有各种库可以帮助注入这些依赖项(Ninject、AutoFac 等)。但是如果你不想/不能使用它们,那么你还需要添加一个默认构造函数来设置你对默认具体实现的依赖:

public ManagementController() {
    _modelFactory = new ModelFactory();
}

这允许您创建 IModelFactory 的 Stubbed/Mocked/Substituted 实现,并将其注入到您的控制器/其他 class 测试中。因此,您的测试可能会像这样开始:

List<ClusterNodeDetails> ClusterNodes = new List<ClusterNodeDetails>();
List<DDL_ClusterName> DropDownListClusterName = new List<DDL_ClusterName>();

var model = new ClusterManagementModel()
{
    ClusterNodeDetailsList = ClusterNodes,
    DropDownListClusterName = DropDownListClusterName,
    CurrentClusterId = 1,
    CurrentClusterName = "UnitTesting",
    HStatus = "True",
    IStatus = "Success"
};

var modelFactory = Substitute.For<IModelFactory>();
modelFactory.CreateClusterManagementModel( /* args for model creation */).Returns(model);

var sut = new ManagementController(modelFactory);
var result = sut.Manage("1") as ActionResult;

您还需要考虑您要测试的是什么。通过提取依赖项,您可以专注于控制器中的逻辑,并将测试重点放在该逻辑上。当您开始使用 Mocks 时,很容易陷入您实际上根本没有测试任何东西的情况,除了您是否正确设置了 Mocks 之外。请记住,它们的存在是为了帮助您重现您需要强制生产代码遵循特定流程的特定场景,而不是替换生产代码中包含的逻辑。