Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I pass dynamic objects into an NUnit TestCase function?

Tags:

c#

nunit

I am writing a data-intensive application. I have the following tests. They work, but they're pretty redundant.

[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); } 

The same properties are modified at the beginning, just as children of different container objects, and a couple of values in the assertion change at the end.

I need to write a few dozen of these, checking different properties. So I want to parameterize the test. The trick is passing the container object as a parameter to the test. The container object is instantiated in the test fixture SetUp.

I want to achieve something like this:

[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); } 

But that doesn't work and I'm not sure how to make it work, or if it's possible.

like image 346
Alexander Garden Avatar asked Nov 19 '10 00:11

Alexander Garden


People also ask

Does NUnit have data provider?

All of the built-in attributes allow for data to be provided programmatically, but NUnit does not have any attributes that fetch the data from a file or other external source.

Which attribute is used to set custom data on a test in the NUnit framework?

TestCase Attribute. The TestCase attribute in NUnit marks a method with parameters as a test method. It also provides the inline data that needs to be used when that particular method is invoked.

How do you write multiple test cases in NUnit?

If you add a second parameter with the Values attribute, for per value of the first parameter, NUnit will add a test for every value of the second parameter. Another way to avoid having to write duplicate tests when testing the same behaviour with different inputs is to use TestCase attribute on the test itself.


1 Answers

I tracked it down. I can't pass an instantiated object into a test via TestCase because attributes are strictly for static meta-data. But the NUnit team has a solution for that, TestCaseSource. The post on the NUnit list that answered the question is here.

Here is what my solution now looks like:

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); } 

It is not as pretty as I hoped and is not as easy to read. But it did succeed on cutting down code duplication, which should make things easier to maintain and fix.

like image 51
Alexander Garden Avatar answered Sep 19 '22 14:09

Alexander Garden