You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在NUnit中使用不同对象作为测试用例以消除代码冗余?

问题:使用NUnit TestCase特性合并重复安装测试方法是否可行?

我正尝试为不同产品(以类形式存在)及不同时间版本编写更新测试。当前有两个重复的安装测试方法,分别针对去年和前年发布的产品,执行安装并验证是否成功,这是更新测试的前置步骤。为消除代码冗余,我尝试使用TestCase特性将其合并为一个测试方法,但未能成功实现,请问这种方式是否可行?

相关代码如下:

测试类定义:

public class UpdateTest 
{
    private static Product ProductLastYear;
    private static Product ProductTwoYearsAgo;
    public UpdateTest(Product product)
    {
        var previousReleasedProducts = new Products();
        ProductLastYear = previousReleasedProducts.GetProduct(Years.GetLastYear());
        ProductTwoYearsAgo = previousReleasedProducts.GetProduct(Years.GetTwoYearsAgo());
    }
}

原重复测试代码:

[Test, Category("UpdateLastYear"), Order((int) NunitTestOrderEnum.Order.First)]
public void InstallPreviousReleasedProduct()
{
    using (var controller = new BootstrapperController(ProductLastYear))
    {
        controller.Install();
    }

    var successfulInstallation = InstallationValidator.ValidateInstall(ProductLastYear);
    Assert.That(successfulInstallation, Is.True);
}

[Test, Category("UpdateTwoYearsAgo"), Order((int) NunitTestOrderEnum.Order.First)]
public void InstallTwoYearsAgoProduct()
{
    using (var controller = new BootstrapperController(ProductTwoYearsAgo))
    {
        controller.Install();
    }

    var successfulInstallation = InstallationValidator.ValidateInstall(ProductTwoYearsAgo);
    Assert.That(successfulInstallation, Is.True);
}

尝试的合并代码(未成功):

[TestCase(ProductLastYear), Category("UpdateLastYear"), Order((int) NunitTestOrderEnum.Order.First)]
[TestCase(ProductTwoYearsAgo), Category("UpdateTwoYearsAgo"), Order((int) NunitTestOrderEnum.Order.First)]
public void InstallPreProduct(Product product)
{
    using (var controller = new BootstrapperController(product))
    {
        controller.Install();
    }

    var successfulInstallation = InstallationValidator.ValidateInstall(product);
    Assert.That(successfulInstallation, Is.True);
}

解答

直接使用[TestCase]传入Product类实例的方式不可行,原因是NUnit要求[TestCase]的参数必须是编译时常量(如字符串、数值、枚举值),而ProductLastYear和ProductTwoYearsAgo是运行时初始化的静态对象,无法作为[TestCase]的参数使用,编译或运行时会报错。

要实现合并测试方法的目标,推荐使用NUnit的[TestCaseSource]特性,它支持返回运行时生成的测试数据,同时可以为每个测试用例单独配置分类、顺序等属性。

修正方案一:基础版TestCaseSource

  1. 先调整测试类的初始化逻辑,使用NUnit的[OneTimeSetUp]替代构造函数做一次性初始化(更符合NUnit的测试生命周期规范):
public class UpdateTest 
{
    private static Products _previousReleasedProducts;

    [OneTimeSetUp]
    public void Setup()
    {
        _previousReleasedProducts = new Products();
    }
}
  1. 定义测试数据源方法,返回需要测试的Product实例:
public static IEnumerable<Product> PreviousProductTestCases()
{
    yield return _previousReleasedProducts.GetProduct(Years.GetLastYear());
    yield return _previousReleasedProducts.GetProduct(Years.GetTwoYearsAgo());
}
  1. 改造测试方法,关联数据源:
[Test, TestCaseSource(nameof(PreviousProductTestCases)), Order((int)NunitTestOrderEnum.Order.First)]
public void InstallPreProduct(Product product)
{
    using (var controller = new BootstrapperController(product))
    {
        controller.Install();
    }

    var successfulInstallation = InstallationValidator.ValidateInstall(product);
    Assert.That(successfulInstallation, Is.True);
}

修正方案二:带自定义分类的TestCaseSource

如果需要为每个测试用例单独设置Category,可以返回TestCaseData对象来配置更多属性:

public static IEnumerable PreviousProductTestCasesWithCategories()
{
    var lastYearProduct = _previousReleasedProducts.GetProduct(Years.GetLastYear());
    yield return new TestCaseData(lastYearProduct)
        .SetCategory("UpdateLastYear");
    
    var twoYearsAgoProduct = _previousReleasedProducts.GetProduct(Years.GetTwoYearsAgo());
    yield return new TestCaseData(twoYearsAgoProduct)
        .SetCategory("UpdateTwoYearsAgo");
}

对应的测试方法:

[Test, TestCaseSource(nameof(PreviousProductTestCasesWithCategories)), Order((int)NunitTestOrderEnum.Order.First)]
public void InstallPreProduct(Product product)
{
    // 测试逻辑不变
}

内容的提问来源于stack exchange,提问作者kklaw

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 06:10:58