如何使用 FluentAssertions 在 xunit 中测试两个对象

How to test two objects in xunit using FluentAssertions

我有一个矩阵 class,另一个 class 正在使用该矩阵稍微改变它。我想测试两个矩阵,一个来自矩阵 class,另一个来自矩阵 class,另一个已经改变,所以我可以确认它们不一样。

类似这样。

[Fact]
public void MatrixFromMatrixIsntTheSameThanMatrixFromMineSweeper()
{
    Matrix _matrix = new Matrix(4, 4);
    MineSweeper mineSweeper = new MineSweeper(4, 4, 2);

    mineSweeper.Matrix.Should().NotBe(_matrix);
}

问题是 Be/NotBe 似乎正在使用对象的引用,所以总是 returns false 因为它们不一样。我也试过 NotBeSameAs, NotBeEquivalentTo.

这些是 Matrix 和 MineSweeper class。

矩阵Class

public struct Coordinate
{
    public int X;
    public int Y;

    public Coordinate(int x, int y)
        => (X, Y) = (x, y);
}

public class Matrix
{
    private readonly int _M, _N;
    private readonly Cell[,] _matrix;
    private const char InitValue = '.';

    public Matrix(int m,  int n)
    {
        (_M, _N) = (m, n);
        _matrix = new Cell[m, n];
        Initialize();
    }

    private void Initialize()
    { 
        for (int m = 0; m < _M; m++)
            for (int n = 0; n < _N; n++)
                _matrix[m, n] = new Cell(InitValue);
    }

    public Cell At(Coordinate coordinate) 
        => _matrix[coordinate.X, coordinate.Y];
    
    public void SetMine(Coordinate coordinate)
    { 
        _matrix[coordinate.X, coordinate.Y] = new Cell('*');
    }
}

扫雷Class

public class MineSweeper
{
    private readonly int _m, _n, _numMines;
    public Matrix Matrix { get; }

    public MineSweeper(int m, int n, int numMines)
    {
        (_m, _n, _numMines) = (m, n, numMines);
        Matrix = new Matrix(m, n);
        SetMines();
    }

    private void SetMines()
    {
        HashSet<Coordinate> minesSet = new HashSet<Coordinate>();
        Random rnd = new Random();

        while (minesSet.Count != _numMines)
            minesSet.Add(new Coordinate(rnd.Next(0, _m), rnd.Next(0, _n)));

        foreach (Coordinate coordinate in minesSet)
            Matrix.SetMine(coordinate);
    }
}

查看您对元组的使用情况,您使用的是最新的 .NET 版本。这使您可以访问 record,我建议您将其用于 Cell 结构。

public record struct Cell (char Value);

记录带有隐含的构造函数和相等性比较。相等比较对您很重要,因为要比较两个 Matrix 对象,您需要确保它们 Cell[,] 的内容相同。

您现在有两个选择:

1。应该()。等于()

适用于 IEnumerable。所以如果你想比较两个 Matrix 对象,你想公开你的 Cell[,] 数组的内容并比较两者。您使用 Equal() 是因为您想要比较项目的顺序。不要使用 BeEquivalentTo() 因为它不关心顺序。 See here for the different enumerable comparisons.

public class Matrix {
  ...
  // Expose your array as an IEnumerable
  public IEnumerable<Cell> Cells => _matrix.OfType<Cell>();
}

// And compare the contents in sequence
public void Test(){
    // These have 1 Mine in the same location:
    Matrix m1 = new(4,4); m1.SetMine(new(1,1));
    Matrix m2 = new(4,4); m2.SetMine(new(1,1));
    // 1 Mine in a different location:
    Matrix xx = new(4,4); xx.SetMine(new(2,2));

    // Same contents in the same order
    m2.Cells.Should().Equal(m1.Cells);
    // Same contents different order, are NOT Equal
    xx.Cells.Should().NotEqual(m1.Cells);
    // But are Equivalent
    xx.Cells.Should().BeEquivalentTo(m1.Cells);

}

2。应该().Be()

如果你想严格封装,并且不想将 Cell[,] 的内容公开为 public,那么你将不得不定义你的相等比较2 Matrix 个对象。这允许您使用 Be() 来调用对象的 Equals() 方法。

(下面代码的Here's a full fiddle)

public class Matrix {
    ...
    /* Easiest way to compare two Cell collections is to join
       the chars into a string, and perform string comparison.
       
       We could go through the two arrays and compare the contents 
       one by one, but a good programmer is a lazy one.
    */
    private string CellsAsString() // private so the public can't see it
        => string.Concat(_matrix.OfType<Cell>().Select(c => c.Value));

    /* Now Override the Equality comparison of the Object */
    public override bool Equals(object other)
        => this.CellsAsString().Equals((other as Matrix)?.CellsAsString());
    // Note that we can access private methods of another object
    // as long as it's the same class as `this`.

}

您的比较现在将是:

Matrix m1 = new(4,4); m1.SetMine(new(1,1));
Matrix m2 = new(4,4); m2.SetMine(new(1,1));
Matrix xx = new(4,4); xx.SetMine(new(2, 2));

m2.Should().Be(m1);
xx.Should().NotBe(m1);

通常我们推荐 BeEquivalentTo,但由于您的 Matrix class 不公开任何 public 字段或属性,唯一的其他选择是 NPras 在选项 2 中建议。