C# 如何将动态对象传递到NUnit测试用例函数中?
我正在编写一个数据密集型应用程序。我有以下测试。它们可以工作,但它们是多余的C# 如何将动态对象传递到NUnit测试用例函数中?,c#,nunit,C#,Nunit,我正在编写一个数据密集型应用程序。我有以下测试。它们可以工作,但它们是多余的 [Test] public void DoSanityCheck_WithCountEqualsZeroAndHouseGrossIsGreater_InMerchantAggregateTotals_SetsWarning() { report.Merchants[5461324658456716].AggregateTotals.ItemCount = 0; report.Merchants[546
[Test]
public void DoSanityCheck_WithCountEqualsZeroAndHouseGrossIsGreater_InMerchantAggregateTotals_SetsWarning()
{
report.Merchants[5461324658456716].AggregateTotals.ItemCount = 0;
report.Merchants[5461324658456716].AggregateTotals._volume = 0;
report.Merchants[5461324658456716].AggregateTotals._houseGross = 1;
report.DoSanityCheck();
Assert.IsTrue(report.FishyFlag);
Assert.That(report.DataWarnings.Where(x=> x is Reports.WarningObjects.ImbalancedVariables && x.mid == 5461324658456716 && x.lineitem == "AggregateTotals").Count() > 0);
}
[Test]
public void DoSanityCheck_WithCountEqualsZeroAndHouseGrossIsGreater_InAggregateTotals_SetsWarning()
{
report.AggregateTotals.ItemCount = 0;
report.AggregateTotals._volume = 0;
report.AggregateTotals._houseGross = 1;
report.DoSanityCheck();
Assert.IsTrue(report.FishyFlag);
Assert.That(report.DataWarnings.Where(x=> x is Reports.WarningObjects.ImbalancedVariables && x.mid == null && x.lineitem == "AggregateTotals").Count() > 0);
}
[Test]
public void DoSanityCheck_WithCountEqualsZeroAndHouseGrossIsGreater_InAggregateTotalsLineItem_SetsWarning()
{
report.AggregateTotals.LineItem["WirelessPerItem"].ItemCount = 0;
report.AggregateTotals.LineItem["WirelessPerItem"]._volume = 0;
report.AggregateTotals.LineItem["WirelessPerItem"]._houseGross = 1;
report.DoSanityCheck();
Assert.IsTrue(report.FishyFlag);
Assert.That(report.DataWarnings.Where(x=> x is Reports.WarningObjects.ImbalancedVariables && x.mid == null && x.lineitem == "WirelessPerItem").Count() > 0);
}
相同的属性在开始时被修改,就像不同容器对象的子对象一样,断言中的两个值在结束时发生更改
我需要写几十个,检查不同的属性。所以我想参数化测试。诀窍是将容器对象作为参数传递给测试。容器对象在测试夹具设置中实例化
我想实现这样的目标:
[TestCase(report.AggregateTotals.LineItem["WirelessPerItem"], 0, "WirelessPerItem")]
[TestCase(report.AggregateTotals, 4268435971532164, "AggregateTotals")]
[TestCase(report.Merchants[5461324658456716].AggregateTotals, 5461324658456716, "WirelessPerItem")]
[TestCase(report.Merchants[4268435971532164].LineItem["EBTPerItem"], 4268435971532164, "EBTPerItem")]
public void DoSanityCheck_WithCountEqualsZeroAndHouseGrossIsGreater_TestCase_SetsWarning(object container, long mid, string field)
{
container.ItemCount = 0;
container._volume = 0;
container._houseGross = 1;
report.DoSanityCheck();
Assert.IsTrue(report.FishyFlag);
Assert.That(report.DataWarnings.Where(x=> x is Reports.WarningObjects.ImbalancedVariables && x.mid == mid && x.lineitem == field).Count() > 0);
}
但是这不起作用,我不知道如何使它起作用,或者它是否可行。如果有一个私有方法、基类方法或帮助类来为您实现这一点,会容易得多 对于我的单元测试,我需要很多模拟实体,因为它是一个数据密集型应用程序。我已经创建了一个模拟存储库结构,它可以动态创建初始化的实体,我可以将这些实体组合起来在内存中构建一个具有代表性的数据库结构 像这样的东西可能对你有用:
// Wild guess at the class name, but you get the idea
private void InitializeTotals(AggregateItem item)
{
item.ItemCount = 0;
item._volume = 0;
item._houseGross = 1;
}
[Test]
public void DoSanityCheck_WithCountEqualsZeroAndHouseGrossIsGreater_InMerchantAggregateTotals_SetsWarning()
{
InitializeTotals(report.Merchants[5461324658456716].AggregateTotals);
report.DoSanityCheck();
Assert.IsTrue(report.FishyFlag);
Assert.That(report.DataWarnings.Where(x => x is Reports.WarningObjects.ImbalancedVariables && x.mid == 5461324658456716 && x.lineitem == "AggregateTotals").Count() > 0);
}
[Test]
public void DoSanityCheck_WithCountEqualsZeroAndHouseGrossIsGreater_InAggregateTotals_SetsWarning()
{
InitializeTotals(report.AggregateTotals);
report.DoSanityCheck();
Assert.IsTrue(report.FishyFlag);
Assert.That(report.DataWarnings.Where(x => x is Reports.WarningObjects.ImbalancedVariables && x.mid == null && x.lineitem == "AggregateTotals").Count() > 0);
}
[Test]
public void DoSanityCheck_WithCountEqualsZeroAndHouseGrossIsGreater_InAggregateTotalsLineItem_SetsWarning()
{
InitializeTotals(report.AggregateTotals.LineItem["WirelessPerItem"]);
report.DoSanityCheck();
Assert.IsTrue(report.FishyFlag);
Assert.That(report.DataWarnings.Where(x => x is Reports.WarningObjects.ImbalancedVariables && x.mid == null && x.lineitem == "WirelessPerItem").Count() > 0);
}
我找到了。我无法通过TestCase将实例化对象传递到测试中,因为属性严格用于静态元数据。但是NUnit团队有一个解决方案,TestCaseSource。NUnit名单上回答这个问题的帖子是 下面是我的解决方案现在的样子:
public static IEnumerable<TestCaseData> CountEqualsZeroAndHouseGrossIsGreaterTestCases
{
get
{
yield return new TestCaseData(report, report.Merchants[4268435971532164].LineItem["EBTPerItem"], 4268435971532164, "EBTPerItem").SetName("ReportMerchantsLineItem");
yield return new TestCaseData(report, report.Merchants[5461324658456716].AggregateTotals, 5461324658456716, "WirelessPerItem").SetName("ReportMerchantsAggregateTotals");
yield return new TestCaseData(report, report.AggregateTotals, null, "AggregateTotals").SetName("ReportAggregateTotals");
yield return new TestCaseData(report, report.AggregateTotals.LineItem["WirelessPerItem"], null, "WirelessPerItem").SetName("ReportAggregateTotalsLineItem");
}
}
[TestCaseSource("CountEqualsZeroAndHouseGrossIsGreaterTestCases")]
public void DoSanityCheck_WithCountEqualsZeroAndHouseGrossIsGreater_TestCase_SetsWarning(Reports.ResidualsReport report, Reports.LineItemObject container, long? mid, string field)
{
container.ItemCount = 0;
container._volume = 0;
container._houseGross = 1;
report.DoSanityCheck();
Assert.IsTrue(report.FishyFlag);
Assert.That(report.DataWarnings.Where(x=> x is Reports.WarningObjects.ImbalancedVariables && x.mid == mid && x.lineitem == field).Count() > 0);
}
公共静态IEnumerable CountEqualsZeroAndHouseGrossIsGreaterTestCases
{
得到
{
返回新的TestCaseData(report,report.Merchants[4268435971532164].LineItem[“EBTPerItem”],4268435971532164,“EBTPerItem”).SetName(“ReportMerchantsLineItem”);
收益返回新的TestCaseData(report,report.Merchants[5461324658456716].AggregateTotals,5461324658456716,“WirelessPerItem”).SetName(“ReportMerchantsAggregateTotals”);
返回新的TestCaseData(report,report.AggregateTotals,null,“AggregateTotals”).SetName(“ReportAggregateTotals”);
返回新的TestCaseData(report,report.AggregateTotals.LineItem[“WirelessPerItem”],null,“WirelessPerItem”).SetName(“ReportAggregateTotalsLineItem”);
}
}
[TestCaseSource(“CountEqualsZeroAndHouseGrossIsGreaterTestCases”)]
public void DoSanityCheck_with CountEqualsZeroAndHouse GrossisMorger_TestCase_SetsWarning(Reports.ResidualsReport,Reports.LineItemObject容器,long?mid,字符串字段)
{
container.ItemCount=0;
容器。_体积=0;
集装箱。_houseGross=1;
report.DoSanityCheck();
Assert.IsTrue(report.FishyFlag);
Assert.That(report.DataWarnings.Where(x=>x是Reports.WarningObjects.unbalancedVariables&&x.mid==mid&&x.lineitem==field).Count()>0);
}
它不像我希望的那么漂亮,也不像我希望的那么容易阅读。但它确实成功地减少了代码重复,这将使维护和修复更加容易。我有时传递我解析的字符串,我认为它读起来非常好 例如:
[TestCase("15°", "-10°", 25, typeof(Degrees))]
[TestCase("-10°", "15°", -25, typeof(Degrees))]
[TestCase("-10°", "0°", -10, typeof(Degrees))]
[TestCase("-90°", "1.5707 rad", -3.1414, typeof(Radians))]
[TestCase("1.5707 rad", "-90°", 3.1414, typeof(Radians))]
[TestCase("1.5707 rad", "1.5707 rad", 0, typeof(Radians))]
public void SubtractionTest(string lvs, string rvs, double ev, Type et)
{
var lv = Angle.Parse(lvs);
var rv = Angle.Parse(rvs);
var diff = lv - rv;
Assert.AreEqual(ev, diff.Value, 1e-3);
Assert.AreEqual(et, diff.Unit.GetType());
}
[测试]
[TestCase(“文本框”,true,“文本为空”,null,false)]
[TestCase(“文本框”,false,“文本为空”,null,true)]
公共无效测试组件验证和验证文本是否为强制设置(字符串文本框、布尔为强制、字符串验证文本、字符串值、布尔期望值)
{
//安排
var mockPublicPortalService=new Mock();
PublicAssessmentController=新的PublicAssessmentController(mockPublicPortalService.Object);
//设置组件属性
var Component=新组件()
{
ComponentDatatype=文本框,
IsMandatory=IsMandatory,
ValidationText=ValidationText,
价值=价值
};
var context=新的ValidationContext(组件);
//表演
var results=新列表();
var isModelStateValid=Validator.TryValidateObject(组件、上下文、结果、true);
//断言
AreEqual(expectedValue,isModelStateValid);
if(isModelStateValid==false)
{
Assert.IsTrue(results.Any(x=>x.ErrorMessage==validationText));
};
}
这是一个改进,但仍然留下了大量冗余。很难阅读这些代码并快速了解每次迭代中测试的要点。参数可以清楚地表明,相同的东西正在不同级别上进行测试。所有这些测试都将合并为一个测试。不建议将所有测试合并为一个测试。如果您针对不同的问题进行了不同的测试,那么更容易找出哪些是正确的,哪些是错误的。如果你在一个测试中投入太多,那么你一次测试太多,解决问题就变得更加困难。有一个很好的演讲,也谈到了这些问题。对。但是对于参数化测试,我只编写了一次代码,但它的运行就好像每一组参数都是一个单独的测试。每个测试用例在NUnit测试运行程序中都有自己的行。因此,仍然很清楚哪个部分失败了,但是代码冗余被消除了,这节省了编写时间,而且更易于阅读。我认为如果使用C#6+,CountequalsZeroAndHouseCrossGreaterTestCases属性应该是static的,而不是将名称用作可以使用“nameof”的字符串。[TestCaseSource(nameof(CountEqualsZeroAndHouseGrossIsGreaterTestCases)),这使它具有强类型。从NUnit 3开始,TestCaseSource也仅限于静态源。@buckminst到NUnit 3,首选的解决方案是什么?请想一想。上面的示例似乎缺少了“static”关键字,因此无法正常工作:publicstatic IEnumerable countequalsZeroAndHouseGrossisgreeaterTestCases不直接在模型中输入,而是输入测试元素
[Test]
[TestCase("textbox", true, "Text is empty", null, false)]
[TestCase("textbox", false, "Text is empty", null, true)]
public void Test_Component_Validation_and_ValidationText__Whether_IsMandatory_IsSet(string textbox, bool isMandatory, string validationText, string value, bool expectedValue)
{
// Arrange
var mockPublicPortalService = new Mock<IPublicPortalService>();
PublicAssessmentController controller = new PublicAssessmentController(mockPublicPortalService.Object);
// Set Component properties
var Component = new Component()
{
ComponentDatatype = textbox,
IsMandatory = isMandatory,
ValidationText = validationText,
Value = value
};
var context = new ValidationContext(Component);
// Act
var results = new List<ValidationResult>();
var isModelStateValid = Validator.TryValidateObject(Component, context, results, true);
// Assert
Assert.AreEqual(expectedValue, isModelStateValid);
if (isModelStateValid == false)
{
Assert.IsTrue(results.Any(x => x.ErrorMessage == validationText));
};
}