假设我使用 Moq 对 Entity Framework 6 进行了以下单元测试:
public void Save_Employee_via_context()
{
var MockContext = new Mock<DcmDataContext>();
var MockSet = new Mock<DbSet<Employee>>();
MockContext.Setup(m => m.Employees).Returns(MockSet.Object);
var service = new GeneralService(MockContext.Object);
//Test valid inputs
for (int i = 0; i < TestData.ValidEmployees.Count; i++)
{
service.AddEmployee(TestData.ValidEmployees[i]);
//veryfy that it was properly inserted
Assert.AreEqual(TestData.ValidEmployees[i],MockSet.Object.Find(TestData.ValidEmployees[i].EmployeeID));
}
//Ensure that the proper methods were called each time. It is implied that this happened if the above
//Assert methods passed, but double checking never killed anybody
MockSet.Verify(m => m.Add(It.IsAny<Employee>()), Times.Exactly(TestData.ValidEmployees.Count));
MockContext.Verify(m => m.SaveChanges(), Times.Exactly(TestData.ValidEmployees.Count));
//Test invalid Inputs
MockSet = new Mock<DbSet<Employee>>();
//InvalidEmployees is a Dictionary<Employee,Type>, where Type is the type of exeption that should eb thrown if
//You attempt to add that Employee
foreach (var pair in TestData.InvalidEmployees)
{
try
{
service.AddEmployee(pair.Key);
//AddEmployee *SHOULD* throw an exception here here.. if not...
Assert.Fail();
}
catch (Exception ex)
{
//Was it the exception that I was expecting to catch?
Assert.Equals(ex.GetType(), pair.Value);
}
}
//ensure that nothing new has been added (redundant, I know, but it doesn't hurt)
MockSet.Verify(m => m.Add(It.IsAny<Employee>()), Times.Never);
MockContext.Verify(m => m.SaveChanges(), Times.Exactly(TestData.ValidEmployees.Count));
}
TestData
是我拥有的静态类,它包含我要测试的每种模型类型的列表,以及每种模型类型的几个测试用例,包括有效和无效输入。
我这样创建我的测试是因为我的对象可能相当大(Employee
例如,有大约 15 个属性),因此我想要运行大量的测试用例以使每个测试都彻底。我不想复制/粘贴每个需要它的方法的每个测试样本数据数组,所以我想将它存储在一个静态容器中。
但是,我觉得这会带来问题。例如, 的属性之一Employee
是Position
。你知道,他们有什么工作。它是必需的属性,如果该位置为空或数据库中尚不存在,则应引发异常。这意味着为了使上述测试有效,我还需要一些模拟位置。哦,但是每个职位都有一个Department
属性……所以也需要设置……
你知道我要去哪里吗?如果没有一整套测试数据来测试它,我如何正确测试我的代码?那么,我想我将不得不编写一整套测试数据。我做到了。
问题是,我把它放在哪里?我决定将所有内容都放入 TestData 类中。
然而,这提出了一系列问题。初始化是最大的一项,因为我觉得我必须对我的测试数据进行中性处理才能使初始化更加可行。例如,我所有的导航属性可能都必须是null
. 我怎么能让我的ValidEmployees
每个人都有一个List<Clients>
,并且每个Client
人都有一个分配Employee
,而没有再次将每个 Employee 复制为每个人都将拥有的属性Client
,并且List<Employee>
每个Position
人都将拥有。在 ValidClientsClients = {ValidClients[0],ValidClients[1]
内部ValidEmployees
和内部拥有不是很好吗?SalesRepresentative = ValidEmployees[0]
我也觉得我需要导航数据。将要
Assert.AreEqual
(
TestData.ValidEmployees[i],
MockSet.Object.Find(TestData.ValidEmployees[i].EmployeeID
)
如果ValidEmployees 中没有navigationData,仍然返回true?这是否意味着我应该找到另一种确保状态的方法?
无论如何,这些都是我遇到的问题。我只是设置我的单元测试完全错误吗?我还应该如何获得健壮、独立、干燥和准确的单元测试?我在这里想念什么?
感谢任何帮助,即使这意味着以不同的心态从头开始。这是我第一个非常认真地对待测试的项目,但我觉得它进展得不太顺利。因此,对于文字墙感到抱歉。有时我觉得我没有问正确的问题来到达我想去的地方。