为什么这个CollectionAssert.AreEquivalent()测试失败了?

时间:2012-12-26 22:40:14

标签: c# linq unit-testing

正如this question中所述,我正在研究一种方法,该方法从一个List<FileInfo>返回另一个List<FileInfo>中不存在的元素。我已经实现了Nawfal的解决方案如下:

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

我为SourceFiles设置的数据是:

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

DestFiles是:

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

当我单步执行代码并检查列表的值时,这似乎会返回预期的结果。但是单元测试失败了,代码如下:

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

即使resultexpectedResult具有相同的内容 - 两个列表都有一个元素具有相同的文件路径和相同的其他属性 - 测试失败并显示消息:

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

expectedResult确实发生了U:\folder1\d.txt。我想也许问题是我正在比较两个对象的内存地址而不是那些对象的内容,但我认为AreEquivalent()正在比较属性。那不是这样吗?

编辑:基于有关比较属性而不是地址的建议,我使用了此Assert,这允许测试通过:

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

3 个答案:

答案 0 :(得分:7)

可能因为FileInfo是引用类型而默认比较器只是检查两个元素的地址是否相等。由于FileInfo已被密封,因此您无法从中获取并覆盖相等比较器。在我看来,最好的选择是编写自己的集合比较器方法(因为你无法将IEqualityComparer实例传递给CollectionAssert.AreEquivalent)。

答案 1 :(得分:4)

测试失败,因为您的集合中包含不同的对象。如果您有2个引用同一文件的FileInfo类实例,并且您致电instanceA.Equals(instanceB),则结果为false

如果您可以将代码更改为使用字符串而不是FileInfo,则可以按照您的预期进行操作。

答案 2 :(得分:1)

在我看来,我可以建议两种比你的方法更好的方法:)

  1. 选择2个文件名集合并比较这些集合:

    CollectionAssert.AreEquivalent(
        result.Select(fi => fi.FullName).ToArray(),
        expectedResult.Select(fi => fi.FullName).ToArray()
    );
    // ToArray() is added just for better output when test fails.
    
  2. 使用用户定义的比较器并比较FileInfo列表:

    Assert.That(
        result,
        Is
            .EquivalentTo(expectedResult)
            .Using((Comparison<FileInfo>)((fi1, fi2) => fi1.FullName.CompareTo(fi2.FullName)))
    );
    
  3. 在以下情况下,您当前使用两个foreach循环的实现不会失败:

    result =
        u:\folder1\a.txt
        u:\folder1\a.txt
    
    expectedResult =
        u:\folder1\a.txt
    

    是的,文件列表似乎不是真实的情况,但通常用两个循环替换AreEquivalent() / Is.EquivalentTo()并不是一个好主意。