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

如何在C#的NUnit测试中传递对象并测试Income.Create方法

解决NUnit测试自定义类对象的问题

原测试代码的问题

  1. 测试方法参数未配置数据源:NUnit不会自动识别带参数的测试方法,必须通过[TestCase]或[TestCaseSource]指定测试数据
  2. 循环逻辑错误:遍历列表时调用bLL.Create(income)而非bLL.Create(item),导致始终使用同一个对象(即使参数能传入)
  3. 业务代码语法错误:原Create方法的if条件多了一个右括号,修正后应为:
    if ((income.Date is null) || (income.Amount == 0) || (income.Payee_ID == 0))
    

正确的测试实现方式

方式1:使用[TestCaseSource]实现参数化测试

这种方式适合将测试数据与测试逻辑分离,方便扩展测试用例:

namespace Test_Layer
{
    [TestFixture]
    public class NunitTests
    {
        // 定义合法测试用例数据源
        private static IEnumerable<Income> ValidIncomeTestCases()
        {
            yield return new Income
            {
                Date = "01-01-2000",
                Amount = 1000,
                Payee_ID = 1,
                Payor = "Bob",
                Description = "Contract no 1"
            };
            yield return new Income
            {
                Date = "02-01-2000",
                Amount = 1500,
                Payee_ID = 2,
                Payor = "Jimmy",
                Description = "Contract no 2"
            };
        }

        // 定义非法测试用例数据源(覆盖必填项缺失场景)
        private static IEnumerable<TestCaseData> InvalidIncomeTestCases()
        {
            // Date为null的情况
            yield return new TestCaseData(new Income
            {
                Date = null,
                Amount = 1000,
                Payee_ID = 1
            }).Returns((false, "Fill all the required fields!"));
            
            // Amount为0的情况
            yield return new TestCaseData(new Income
            {
                Date = "01-01-2000",
                Amount = 0,
                Payee_ID = 1
            }).Returns((false, "Fill all the required fields!"));
            
            // Payee_ID为0的情况
            yield return new TestCaseData(new Income
            {
                Date = "01-01-2000",
                Amount = 1000,
                Payee_ID = 0
            }).Returns((false, "Fill all the required fields!"));
        }

        // 测试合法输入的场景
        [Test]
        [TestCaseSource(nameof(ValidIncomeTestCases))]
        public void IncomeCreate_ValidInput_ReturnsSuccess(Income income)
        {
            var bLL = new Family_Budget_BLL.IncomeBLL();
            var (successResult, errorMessage) = bLL.Create(income);
            
            Assert.Multiple(() =>
            {
                Assert.That(successResult, Is.True);
                Assert.That(errorMessage, Is.Null);
            });
        }

        // 测试非法输入的场景
        [Test]
        [TestCaseSource(nameof(InvalidIncomeTestCases))]
        public (bool, string) IncomeCreate_InvalidInput_ReturnsError(Income income)
        {
            var bLL = new Family_Budget_BLL.IncomeBLL();
            return bLL.Create(income);
        }
    }
}

方式2:在测试方法内直接构造测试用例(适合简单场景)

如果测试用例不多,也可以直接在方法内构造所有场景并逐一验证:

namespace Test_Layer
{
    [TestFixture]
    public class NunitTests
    {
        [Test]
        public void IncomeCreate_TestAllScenarios()
        {
            var bLL = new Family_Budget_BLL.IncomeBLL();

            // 测试合法输入
            var validIncomes = new List<Income>
            {
                new Income
                {
                    Date = "01-01-2000",
                    Amount = 1000,
                    Payee_ID = 1,
                    Payor = "Bob",
                    Description = "Contract no 1"
                },
                new Income
                {
                    Date = "02-01-2000",
                    Amount = 1500,
                    Payee_ID = 2,
                    Payor = "Jimmy",
                    Description = "Contract no 2"
                }
            };

            foreach (var income in validIncomes)
            {
                var (successResult, errorMessage) = bLL.Create(income);
                Assert.Multiple(() =>
                {
                    Assert.That(successResult, Is.True);
                    Assert.That(errorMessage, Is.Null);
                });
            }

            // 测试非法输入:Date为null
            var nullDateIncome = new Income { Date = null, Amount = 1000, Payee_ID = 1 };
            var (nullDateSuccess, nullDateError) = bLL.Create(nullDateIncome);
            Assert.Multiple(() =>
            {
                Assert.That(nullDateSuccess, Is.False);
                Assert.That(nullDateError, Is.EqualTo("Fill all the required fields!"));
            });

            // 测试非法输入:Amount为0
            var zeroAmountIncome = new Income { Date = "01-01-2000", Amount = 0, Payee_ID = 1 };
            var (zeroAmountSuccess, zeroAmountError) = bLL.Create(zeroAmountIncome);
            Assert.Multiple(() =>
            {
                Assert.That(zeroAmountSuccess, Is.False);
                Assert.That(zeroAmountError, Is.EqualTo("Fill all the required fields!"));
            });

            // 测试非法输入:Payee_ID为0
            var zeroPayeeIdIncome = new Income { Date = "01-01-2000", Amount = 1000, Payee_ID = 0 };
            var (zeroPayeeIdSuccess, zeroPayeeIdError) = bLL.Create(zeroPayeeIdIncome);
            Assert.Multiple(() =>
            {
                Assert.That(zeroPayeeIdSuccess, Is.False);
                Assert.That(zeroPayeeIdError, Is.EqualTo("Fill all the required fields!"));
            });
        }
    }
}

关键说明

  • 参数化测试:通过[TestCaseSource]可以批量传入自定义类对象,每个测试用例会单独执行,方便定位问题
  • 场景覆盖:除了合法输入,必须测试必填项缺失的异常场景,保证业务逻辑的完整性
  • Assert.Multiple:使用这个方法可以在一次断言失败后继续执行其他断言,一次性展示所有错误
  • 依赖隔离:如果incomeDAL.Create依赖数据库等外部资源,建议使用Moq等框架模拟DAL层,避免测试依赖外部环境

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 04:35:19