0

At this moment, I am using NUnit to perform comparisons. (I'm open to using a different unit testing framework for this test.) I am using ILGenerator to dynamically invoke a stored procedure that has been mapped via Entity Framework 6.0. (The stored procedure simply selects from a table-valued user-defined function in a SQL Server 2012 database.)

The code seems to work properly, but I am having trouble getting my Assert to pass. Here is what my error looks like:

Expected: equivalent to <  
<CT_EntityDataModel.PROC_CT_Select_udfFacilityHolds_Global_Result>, 
<CT_EntityDataModel.PROC_CT_Select_udfFacilityHolds_Global_Result>, 
<CT_EntityDataModel.PROC_CT_Select_udfFacilityHolds_Global_Result>, 
<CT_EntityDataModel.PROC_CT_Select_udfFacilityHolds_Global_Result>, 
<CT_EntityDataModel.PROC_CT_Select_udfFacilityHolds_Global_Result>, 
<CT_EntityDataModel.PROC_CT_Select_udfFacilityHolds_Global_Result> >

  But was:  < 
<CT_EntityDataModel.PROC_CT_Select_udfFacilityHolds_Global_Result>, 
<CT_EntityDataModel.PROC_CT_Select_udfFacilityHolds_Global_Result>, 
<CT_EntityDataModel.PROC_CT_Select_udfFacilityHolds_Global_Result>, 
<CT_EntityDataModel.PROC_CT_Select_udfFacilityHolds_Global_Result>, 
<CT_EntityDataModel.PROC_CT_Select_udfFacilityHolds_Global_Result>, 
<CT_EntityDataModel.PROC_CT_Select_udfFacilityHolds_Global_Result> >


   at NUnit.Framework.Assert.That(Object actual, IResolveConstraint expression, String message, Object[] args)
   at NUnit.Framework.CollectionAssert.AreEquivalent(IEnumerable expected, IEnumerable actual, String message, Object[] args)
   at NUnit.Framework.CollectionAssert.AreEquivalent(IEnumerable expected, IEnumerable actual)
   at CT.Tests.WpfControlsTests.ControlGeneratingMediator_AreDataProviderResultsPopulatingCorrectly_ReturnsTrue() in WPFControlsTests.cs: line 1338

The summary for the NUnit.Framework.CollectionAssert.AreEquivalent method states:

"Asserts that expected and actual are equivalent, containing the same objects but the match may be in any order."

Since the objects in the collections originate from different sequences of operations, I'm not sure if I want to assert that the objects are the same (or have the same hash); regardless, I want to assert that the objects have matching property values. I am hoping that I won't need to override an equality comparison operation or perform some crazy hack to accomplish this.

Here is the responsible test:

using NUnit.Framework;
// . . . 
[Test]
public void ControlGeneratingMediator_AreDataProviderResultsPopulatingCorrectly_ReturnsTrue()
{
    var instance = SharedSetupSingleton.Instance;
    var methodInfo = instance.GetMethodInfo();
    SimpleLoadDynamicGridMediatorFactory factory = new SimpleLoadDynamicGridMediatorFactory();
    var commandstrategymediator = factory.Build(SimpleMediatorFactory.MediatorType.LoadDynamicGridMediator_Simple, methodInfo);
    var commandstrategymediatorConverted = (LoadDynamicGridMediator)commandstrategymediator;
    commandstrategymediatorConverted.CallStrategy(methodInfo); // we really shouldn't need to pass in the methodInfo when it's already defined during construction.
    var newMediator = factory.Build(SimpleMediatorFactory.MediatorType.ControlGeneratingMediator_Simple, methodInfo);
    newMediator.CallStrategy();
    //newMediator.InputCommandStrategyMediator = commandstrategymediatorConverted;

    var originalResultList = new List<dynamic>();
    // each item should be of type: {CT_EntityDataModel.PROC_CT_Select_udfFacilityHolds_Global_Result}
    // I used the following foreach loops to work around an "InvalidOperationException: The result of a query cannot be enumerated more than once."
    foreach (var item in commandstrategymediatorConverted.ProviderResultSet)
    {
        originalResultList.Add(item);
    }
    var mappedResultList = new List<dynamic>();
    foreach (var item in newMediator.Strategy.Results)
    {
        mappedResultList.Add(item);
    }
    CollectionAssert.AreEquivalent(originalResultList, mappedResultList);
    // Are both of these parameters pulling on the same IEnumerable?
    //Assert.AreEqual(commandstrategymediatorConverted.ProviderResultSet, newMediator.Strategy.Results);
}

(Note: From a best practices perspective, I realize that this test is rather ugly and looks more like an integration test than an actual unit test. If you want to criticize the test, please provide a code sample that offers legitimate improvements to the code. (Keep in mind that the EF objects are resolved at run-time because I have not yet found a way to dynamically invoke them while still preserving resulting type information (i.e. type information about the results returned from a stored procedure invoked via Entity Framework) at compile-time. If you have figured out how to accomplish this, then please say something. (I will want to speak with you.)).

devinbost
  • 4,658
  • 2
  • 44
  • 57

2 Answers2

0

See this answer about public property value comparison. It deals with a single object, though, so you'd need to do the looping over the collections yourself. E.g. order each one by the same field then access each entry in turn in both collections for the same index and apply the comparison operator.

Note that the code in this answer assumes that both objects are of the same type. It's fairly trivial to modify it to accept two different types.

Arguably, though, you would be better off implementing the Equals method (e.g. by looking at an identifying property value), allowing that to be used in collection comparisons and then having a separate test that retrieves just one object via both mechanisms and compares the values in the public properties on each of them using the method mentioned, just to ensure that all values were being filled.

Community
  • 1
  • 1
Josh Gallagher
  • 5,211
  • 2
  • 33
  • 60
0

With FluentAssertions (which supports all major unit testing frameworks) you can do this

originalResultList.ShouldAllBeEquivalentTo(mappedResultList);

to assertion that both collections are structurally equivalent.

Dennis Doomen
  • 8,368
  • 1
  • 32
  • 44