单元测试数据存储

6
假设我有一个具有“storeData(key,data)”和“getData(key)”方法的接口。我应该如何测试具体实现?我应该检查是否已将数据正确设置在存储介质中(例如SQL数据库),还是只需使用getData检查是否返回正确的数据即可?
如果我在数据库中查找数据,则感觉我也在测试方法的内部,但仅检查是否返回相同的数据似乎不完整。
5个回答

2

您似乎被单元测试的热潮所吸引,但实际上您要做的是一个集成测试。从相同的键中设置并返回相同的值是一个使用存储引擎模拟实现时进行的单元测试,但测试实际存储(比如数据库)而不是模拟存储,这不再是一个单元测试,而是测试的一个基本部分,听起来像是集成测试。不要将单元测试作为您的“万能钥匙”,而应选择适合具体工作的正确工具。将您的测试划分为更多的层次。


2
在单元测试中,您需要确保方法执行了其应该执行的任务。如果该方法使用依赖项来完成工作,则需要将这些依赖项模拟出来,并确保该方法调用所依赖对象上的方法时传递正确的参数。这样可以在隔离环境中测试代码。
其中一个好处是它可以推动代码设计更好的方向。例如,为了使用模拟,您自然会倾向于使用更松散耦合的依赖注入代码。这使您能够轻松地替换类所依赖的实际对象为模拟对象。同时,您还需要实现接口,这些接口更容易被模拟。这两种做法都是良好的设计模式,可以提高代码质量。
为了测试您的特定示例,例如,您可能需要让您的类依赖于一个工厂来创建连接到数据库的连接和一个构建器来构造通过连接执行的参数化SQL命令。您会将这些对象的模拟版本传递给您的类,并确保调用正确的方法来设置连接和命令、构建正确的命令、执行它并拆除连接。或者,您可以注入已经打开的连接并简单地构建命令并调用它。关键是您的类是基于一个接口或一组接口构建的,您使用模拟来提供实现这些接口的对象,并记录调用和提供您期望从接口(们)使用的正确返回值。

1
在这种情况下,我通常会创建 SetUp 和 TearDown 方法,在我的单元测试之前/之后触发。这些方法将设置我需要的任何测试数据,并在完成时删除任何测试数据。伪代码示例:
Const KEY1 = "somekey"
Const VALUE1= "somevalue"


Const KEY2 = "somekey2"
Const VALUE2= "somevalue2"



Sub SetUpUnitTests()
{
   Insert Into SQLTable(KEY1,VALUE1)
}


//this test is not dependent on the setData Method
Sub GetDataTest()
{
   Assert.IsEqual(getData(KEY1),VALUE1)
}

//this test is not dependent on getData Method
Sub SetDataTest()
{
   storeData(newKey,NewData)
   Assert.IsNotNull(Direct Call to SQL [Select data from table where key=KEY2]) 

}

Sub TearDownUnitTests()
{
   Delete From table Where key in (KEY1, KEY2)
} 

0

我认为这取决于数据以后的使用方式 - 如果你只会使用 storeDatagetData 访问数据,为什么不同时测试这些方法呢?我想有可能会出现错误,稍微难以确定是在 storeData 还是 getData 中,但如果它

  1. 使你的测试更容易实现,并且
  2. 像你所说的那样隐藏内部细节

如果数据将使用其他机制从数据库中读取或插入,则建议按照你所建议的使用 SQL 检查数据库。

@brendan 提出了一个很好的观点 - 无论你决定使用哪种方法,都将向数据库插入数据。在测试之前和之后清除数据是个好主意,以确保你可以获得一致的结果。


0

在我的经验中,将测试和编程结合起来是一种常见的技术,我不会回避使用它。我已经用相同的模式进行过序列化/反序列化、解析和打印。

如果你不想访问数据库,你可以使用一个数据库模拟器。有些人在使用模拟器时有着与你相同的感受——这在某种程度上是实现特定的。像所有的事情一样,这是一种权衡:考虑模拟的好处(速度快,不依赖于数据库)和缺点(不能检测到实际的数据库问题,速度慢)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接