I have a Matrix class, and another class which is using that matrix changing it a little bit. I'd like to test both matrix, one from the matrix class and the other one which has been changed, so I can confirmed they're not the same.
Something like this.
[Fact]
public void MatrixFromMatrixIsntTheSameThanMatrixFromMineSweeper()
{
Matrix _matrix = new Matrix(4, 4);
MineSweeper mineSweeper = new MineSweeper(4, 4, 2);
mineSweeper.Matrix.Should().NotBe(_matrix);
}
The thing is that Be/NotBe
seems is using the reference from the object, so always it returns false because they're not the same. I also have tried with NotBeSameAs
, NotBeEquivalentTo
.
These are the Matrix and MineSweeper class.
Matrix 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('*');
}
}
MineSweeper 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);
}
}
CodePudding user response:
Looking at your usage of tuples, you're using a recent .NET version. This gives you access to record
, which I recommend you use for your Cell
structure.
public record struct Cell (char Value);
Records come with an implied constructor and equality comparison. The equality comparison is important for you, because to compare two Matrix
objects, you would need to make sure the content of their Cell[,]
are identical.
You now have two options:
1. Should().Equal()
Works on IEnumerable
. So if you want to compare two Matrix
objects, you want to expose the contents of your Cell[,]
arrays and compare the two. You use Equal()
because you want to compare the order of items. Don't use BeEquivalentTo()
because it doesn't care about order. 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. Should().Be()
If you want to be strict with encapsulation, and don't want to expose the contents of your Cell[,]
as public, then you're going to have to define your equality comparison between 2 Matrix
objects. This allows you to use Be()
which will call the object's Equals()
method.
(Here's a full fiddle of the code below)
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`.
}
Your comparison will now simply be:
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);
CodePudding user response:
Normally we recommend BeEquivalentTo
, but since your Matrix
class doesn't expose any public fields or properties, the only other option is what NPras suggested in option 2.