这是我为与数据库交互的类编写的集成测试:
[Test]
public void SaveUser()
{
// Arrange
var user = new User();
// Set a bunch of properties of the above User object
// Act
var usersCountPreSave = repository.SearchSubscribersByUsername(user.Username).Count();
repository.Save(user);
var usersCountPostSave = repository.SearchSubscribersByUsername(user.Username).Count();
// Assert
Assert.AreEqual(userCountPreSave + 1, userCountPostSave);
}
在我看来,我无法在不涉及Save
函数的情况下测试SearchSubscriberByUsername
函数,以确定用户是否已成功保存。我意识到集成测试并不是单元测试,它应该一次测试一个代码单元。但理想情况下,如果我可以在每次测试中测试我的存储库类中的一个函数,那将会很好,但我不知道如何实现它。
到目前为止我是如何编写代码还是有更好的方法?
答案 0 :(得分:8)
您的测试有问题。当您测试将数据保存到数据库中时,您应该测试它是否在数据库中,而不是存储库说它在数据库中。
如果您正在测试存储库的功能,那么您无法通过询问它是否已正确完成来验证该功能。这相当于对某人说'你做得对吗?'他们会说是的。
想象一下,存储库永远不会提交。您的测试将正常通过,但数据将不在数据库中。
所以,我要做的是打开数据库的连接(纯SQL)并检查数据是否已正确保存。您只需要在之前和之后选择计数(*)以确保用户已被保存。如果这样做,您也可以避免使用SearchSubscribersByUsername。
如果您正在测试存储库的功能,则根据定义,您无法信任存储库。
答案 1 :(得分:2)
要对“保存”功能进行单元测试,您肯定需要一些值得信赖的通道来检查操作结果。如果您信任SearchSubscribersByUsername
(因为您已经为该功能自行完成了一些单元测试),您可以在此处使用它。
如果您不信任SearchSubscribersByUsername
,并且您认为您的单元测试也可能因为该函数中存在错误(而不是Save
)而中断,则应考虑使用其他渠道(也许您有可能绕过对数据库的SQL访问来检查Save
结果,这可能比SearchSubscribersByUsername
的实现更简单?但是,不要再次重新实现SearchSubscribersByUsername
,这将变得毫无意义。无论哪种方式,您至少需要一些其他可以信任的功能。
答案 2 :(得分:1)
除非您测试的方法返回有关您所做的事情的确切信息,否则我认为没有办法避免调用其他方法。我认为你认为集成测试需要一种不同的单元测试思维方式是正确的。
我仍然会构建专注于单个方法的测试。所以在测试Save()时我可能会使用Search()的功能,但我的重点是Save()的边缘情况。我构建了处理重复插入或无效输入数据的测试。然后我构建了一大堆Search()测试来处理Search()的边缘情况。
现在一种可能的思维方式是Save和Search有一些共性,Search中的错误可能会掩盖Save中的错误。想象一下,例如,如果你有一个缓存层。因此,另一种方法可能是使用其他一些验证机制。例如,对数据库的直接JDBC调用,或者在基础结构中的某个位置替代地引入模拟层。在构建复杂的集成系统时,这种“后门”验证可能是必不可少的。
答案 3 :(得分:0)
就个人而言,我已经写了无数与此非常相似的测试并认为它很好。另一种方法是将数据库存根,以便searchSubscribers永远不会做任何事情,但是我所说的很多工作都没什么用。