使用 Nunit 或 Microsoft.VisualStudio.TestTools.UnitTesting。现在我的断言失败了。
[TestMethod]
public void GivenEmptyBoardExpectEmptyBoard()
{
var test = new Board();
var input = new Board()
{
Rows = new List<Row>()
{
new Row(){Cells = new List<int>(){0,0,0,0}},
new Row(){Cells = new List<int>(){0,0,0,0}},
new Row(){Cells = new List<int>(){0,0,0,0}},
new Row(){Cells = new List<int>(){0,0,0,0}},
}
};
var expected = new Board()
{
Rows = new List<Row>()
{
new Row(){Cells = new List<int>(){0,0,0,0}},
new Row(){Cells = new List<int>(){0,0,0,0}},
new Row(){Cells = new List<int>(){0,0,0,0}},
new Row(){Cells = new List<int>(){0,0,0,0}},
}
};
var lifeOrchestration = new LifeOrchestration();
var actual = lifeOrchestration.Evolve(input);
Assert.AreEqual(expected, actual);
}
您有两个不同的
Board
实例,因此您对 Assert.AreEqual
的调用将会失败。即使它们的整个内容看起来相同,您也是在比较参考,而不是基础值。
您必须指定是什么使两个
Board
实例相等。
你可以在测试中做到这一点:
Assert.AreEqual(expected.Rows.Count, actual.Rows.Count);
Assert.AreEqual(expected.Rows[0].Cells[0], actual.Rows[0].Cells[0]);
// Lots more tests of equality...
或者你可以在课堂上进行:(注意我是即时写的 - 你需要调整它)
public class Board
{
public List<Row> Rows = new List<Row>();
public override bool Equals(object obj)
{
var board = obj as Board;
if (board == null)
return false;
if (board.Rows.Count != Rows.Count)
return false;
return !board.Rows.Where((t, i) => !t.Equals(Rows[i])).Any();
}
public override int GetHashCode()
{
// determine what's appropriate to return here - a unique board id may be appropriate if available
}
}
public class Row
{
public List<int> Cells = new List<int>();
public override bool Equals(object obj)
{
var row = obj as Row;
if (row == null)
return false;
if (row.Cells.Count != Cells.Count)
return false;
if (row.Cells.Except(Cells).Any())
return false;
return true;
}
public override int GetHashCode()
{
// determine what's appropriate to return here - a unique row id may be appropriate if available
}
}
我曾经重写 getHasCode 和 equals,但我从来不喜欢它,因为我不想为了单元测试而更改我的生产代码。 还有就是有点痛。
然后我转向了太多的反思来比较侵入性较小的对象......但这需要大量的工作(很多极端情况)
最后我用:
http://www.nuget.org/packages/DeepEqual/ 效果很好。
更新,6年后:
我现在使用更通用的 .NET 库 Fluentassertions 它的作用与上面相同,但具有更多功能和漂亮的 DSL,具体替换为:https://fluidassertions.com/objectgraphs/
PM> Install-Package FluentAssertions
而且经过几年的经验,我仍然不推荐覆盖路线,我什至认为这是一个不好的做法。如果您不小心,在使用某些集合(例如字典)时可能会引入性能问题。此外,当您有一个真正的业务案例来重载这些方法时,您就会遇到麻烦,因为您已经有这个测试代码了。生产代码和测试代码应该分开,测试代码不应该依赖实现细节或黑客来实现其目标,这使得它们难以维护和理解。
对于简单的对象,例如域对象或 DTO 或实体,您可以简单地将两个实例序列化为字符串并比较该字符串:
var object1Json = JsonConvert.SerializeObject(object1);
var object2Json = JsonConvert.SerializeObject(object2);
Assert.AreEqual(object1Json, object2Json);
这当然有各种警告,因此请评估您的类中的 JSON 是否包含应比较的预期值。
例如,如果您的类包含非托管资源或不可序列化的属性,则将无法正确比较这些资源。默认情况下它也只序列化公共属性。
ExpectedObjects 将帮助您通过属性值比较相等性。它支持:
我喜欢 ExpectedObjects,因为我只需要调用 2 个 API 来断言比较对象相等性:
我想要一个不需要添加依赖项的解决方案,可以使用 VS 单元测试,比较两个对象的字段值,并告诉我所有不相等的字段。这就是我想出来的。请注意,它也可以扩展到使用属性值。
就我而言,这对于比较某些文件解析逻辑的结果非常有效,以确保两个技术上“不同”的条目具有具有相同值的字段。
public class AssertHelper
{
public static void HasEqualFieldValues<T>(T expected, T actual)
{
var failures = new List<string>();
var fields = typeof(T).GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance);
foreach(var field in fields)
{
var v1 = field.GetValue(expected);
var v2 = field.GetValue(actual);
if (v1 == null && v2 == null) continue;
if(!v1.Equals(v2)) failures.Add(string.Format("{0}: Expected:<{1}> Actual:<{2}>", field.Name, v1, v2));
}
if (failures.Any())
Assert.Fail("AssertHelper.HasEqualFieldValues failed. " + Environment.NewLine+ string.Join(Environment.NewLine, failures));
}
}
[TestClass]
public class AssertHelperTests
{
[TestMethod]
[ExpectedException(typeof(AssertFailedException))]
public void ShouldFailForDifferentClasses()
{
var actual = new NewPaymentEntry() { acct = "1" };
var expected = new NewPaymentEntry() { acct = "2" };
AssertHelper.HasEqualFieldValues(expected, actual);
}
}
Assert 方法依赖于对象的 Equals 和 GetHashcode。您可以实现它,但如果在单元测试之外不需要这种对象相等性,我会考虑比较对象上的各个基元类型。 看起来对象足够简单并且重写 equals 并没有真正的必要。
如果您只想比较复杂类型对象的属性, 迭代对象属性将给出所有属性。 您可以尝试下面的代码。
//Assert
foreach(PropertyInfo property in Object1.GetType().GetProperties())
{
Assert.AreEqual(property.GetValue(Object1), property.GetValue(Object2));
}
使用 Net6+,您可以使用 IEqualityComparer。您可以在顶部添加类似的方法,而不必重写类本身。如果您想要更深入的检查,您可能会查找如何处理 GetHashCode
Assert.AreEqual(expected.Rows.Count, actual.Rows.Count, new BoardEqualityComparerMethod());
public class BoardEqualityComparerMethod : IEqualityComparer<Board>
{
public bool Equals(Board x, Board y)
{
if (x == null)
return y == null;
else if (y == null)
return false;
else
//Do a check here using Foreach or creating it's own IEqualityComparer
return x.Rows == y.Rows;
}
public int GetHashCode(Board obj)
{
//do hashing if needed
return obj.GetHashCode();
}
}