Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does this CollectionAssert.AreEquivalent() test fail?

As described in this question, I'm working on a method that returns the elements from one List<FileInfo> that are not present in another List<FileInfo>. I've implemented Nawfal's solution as follows:

public List<FileInfo> SourceNotInDest(List<FileInfo> SourceFiles, List<FileInfo> DestFiles)
{
 var notInDest = SourceFiles.Where(c => !DestFiles.Any(p => p.Name == c.Name)).ToList();
 return notInDest;
}

My data set for SourceFiles is:

u:\folder1\a.txt
u:\folder1\b.txt
u:\folder1\c.txt
u:\folder1\d.txt

DestFiles is:

u:\folder2\a.txt
u:\folder2\b.txt
u:\folder2\c.txt

When I step through the code and examine the lists' values, this appears to return the expected result. But the unit test fails with the following code:

public void SourceNotInDestTest()
    {
        //arrange
        FileListComparer flc = new FileListComparer(); //class that has the list compare method
        FolderReader fr = new FolderReader(); //class for getting FileInfo from folder
        List<FileInfo> expectedResult = new List<FileInfo>();
        expectedResult.Add(new FileInfo(@"U:\folder1\d.txt"));
        List<FileInfo> SourceFiles = fr.fileList(@"U:\folder1");  //gets the FileInfo for each file in the folder
        List<FileInfo> DestFiles = fr.fileList(@"U:\folder2");


        //act
        List<FileInfo> result = flc.SourceNotInDest(FTPFiles, LocalFiles);

        //assert
        CollectionAssert.AreEquivalent(result, expectedResult);
    }

Even though result and expectedResult have the same contents--both lists have one element with the same file path and same other properties--the test fails with the message:

CollectionAssert.AreEquivalent failed. The expected collection contains 1 occurrence(s)
of <U:\folder1\d.txt>. The actual collection contains 0 occurrence(s).

expectedResult does have an occurrence of U:\folder1\d.txt, though. I was thinking maybe the problem is that I'm comparing the memory addresses for two objects instead of the contents of those objects, but I thought the AreEquivalent() was comparing properties. Is that not the case?

EDIT: Based on the advice about comparing properties instead of addresses, I used this Assert instead, which allowed the test to pass:

foreach (FileInfo fi1 in result)
    {
     Assert.IsNotNull(expectedResult.Find(fi2 => fi2.FullName == fi1.FullName));
    }
foreach (FileInfo fi1 in expectedResult)
    {
     Assert.IsNotNull(result.Find(fi2 => fi2.FullName == fi1.FullName));
    }
like image 864
sigil Avatar asked Dec 26 '12 22:12

sigil


2 Answers

Probably because FileInfo is a reference type and the default comparer just checks for the two elements' addresses to be equals. Since FileInfo is sealed, you can't derive from it and override the equality comparers. The best option, in my opinion, would be writing your own collection comparer method (since you can't pass an IEqualityComparer instance to CollectionAssert.AreEquivalent).

like image 68
Mir Avatar answered Nov 15 '22 13:11

Mir


The test is failing because your collections have different objects in them. If you have 2 instances of the FileInfo class that refer to the same file, and you call instanceA.Equals(instanceB), the result is false.

If you could change your code to use strings instead of FileInfos, it would work as you expect it to.

like image 41
Dan Avatar answered Nov 15 '22 11:11

Dan