为什么CollectionAssert.AreEquivalent()测试会失败?

本文关键字:失败 测试 CollectionAssert AreEquivalent 为什么 | 更新日期: 2023-09-27 17:49:32

如本问题所述,我正在研究一种方法,该方法返回一个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));
    }

为什么CollectionAssert.AreEquivalent()测试会失败?

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

测试失败,因为集合中有不同的对象。如果你有两个实例的FileInfo类引用同一个文件,你调用instanceA.Equals(instanceB),结果是false

如果你可以改变你的代码使用字符串而不是FileInfo s,它会像你期望的那样工作。

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

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

在以下情况下,使用两个foreach循环的当前实现不会失败:

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

是的,它似乎不是真正的情况下的文件列表,但一般来说,这不是一个好主意,以替换AreEquivalent()/Is.EquivalentTo()与两个循环。