【问题标题】:How to test two objects in xunit using FluentAssertions如何使用 FluentAssertions 在 xunit 中测试两个对象
【发布时间】:2022-01-21 17:21:57
【问题描述】:

我有一个 Matrix 类,而另一个使用该矩阵的类对其进行了一些更改。我想测试两个矩阵,一个来自矩阵类,另一个已经改变,所以我可以确认它们不一样。

类似的东西。

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

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

问题是Be/NotBe 似乎正在使用来自对象的引用,所以它总是返回 false,因为它们不一样。我也试过NotBeSameAsNotBeEquivalentTo

这些是 Matrix 和 MineSweeper 类。

矩阵类

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('*');
    }
}

扫雷类

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

【问题讨论】:

    标签: c# unit-testing fluent-assertions


    【解决方案1】:

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

    public record struct Cell (char Value);
    

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

    您现在有两个选择:

    1。应该().Equal()

    适用于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[,] 的内容公开,那么您将必须定义 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.
        */
        public 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);
    

    【讨论】:

      【解决方案2】:

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

      【讨论】:

        猜你喜欢
        • 2019-08-25
        • 1970-01-01
        • 2016-11-14
        • 2013-05-04
        • 1970-01-01
        • 1970-01-01
        • 2020-11-03
        • 2022-12-18
        • 1970-01-01
        相关资源
        最近更新 更多