你如何测试你的业务对象?

6

我希望能够使用Visual Studio中的Microsoft测试框架来实现自动化测试,以便于我的软件开发项目。我已经创建了一些测试,总体而言,使用起来相当容易。

有哪些更好的做法可以用于测试业务对象,更具体地说是那些读写数据库的对象呢?

最好是设置一个单独的测试数据库,与开发数据库分开,从用户界面进行测试,并只针对该数据库进行测试吗?基本上只填充它们的垃圾数据。

是否更好地采用某种自我清理的方法,即如果我正在测试AddUser方法,我是否应该添加用户,检查我的测试,然后删除用户?

您是否在单个测试方法中测试每个CRUD方法?

最后,如何验证单个业务规则,例如验证字符串大小是否正确、开始日期是否小于结束日期、CustomerId是否正确等。

我知道这是一个很广泛的问题......只是想寻求一些方向......慢慢来。

更多信息...

有很多好答案!我不确定我能否成功模拟数据库。我正在使用CSLA作为对象的框架。要使用模拟对象进行测试需要进行一些严重的重构。我将研究这个问题。尽管如此,在某些时候,我确实希望测试数据库交互......当使用模拟数据库时,您何时/在何处实际测试数据库通信呢?

另一个问题......最好让每个测试方法都不依赖于其他测试吗?


在这里找到了一些不错的经验法则:http://msdn.microsoft.com/en-us/library/ms379625(VS.80).aspx。同意很多人所说的话。 - mattruma
8个回答

8
理想情况下,您应该拥有不直接访问数据库的业务对象,而是使用辅助对象或某种ORM(对象关系映射)框架。然后,您可以在没有数据库的情况下测试您的BO,可能会模拟一些辅助对象。这可能是最干净的方式,因为您避免了真实数据库的复杂性,并且确实只测试您的业务逻辑。
如果您无法避免将业务规则和数据库访问合并到一个类中(这可能是一个有问题的设计,但有时难以避免),那么您必须针对数据库进行测试。
在这种情况下,唯一合理的选择就是为自动化测试使用单独的数据库。您的测试方法应该在设置时删除所有内容,然后加载所有数据,进行测试并验证结果。
不要试图初始化数据库一次,然后在相同的数据上运行所有测试。一个测试会意外更改数据,其他测试会神秘地失败。我做过这件事并为此感到遗憾...每个测试都必须独立存在。
为了完成所有这些工作,我强烈建议使用某种数据库测试框架。这些框架可帮助您清理数据库,加载必要数据,并将查询结果与预期结果进行比较。我使用DBUnit(用于Java),但其他语言也有许多其他框架可供选择。

谢谢!有哪些数据库测试框架?还是需要自行开发? - mattruma
不,重点是使用现有的框架。我使用DBUnit,http://www.dbunit.org,但也有其他的框架。只需在谷歌上搜索“单元测试数据库”即可。 - sleske

5
我建议您实现业务对象,使其不了解数据库。使用数据访问层上的方法,根据它们的类型正确保存/检索业务对象(即,它在表和相应对象之间具有内部映射)。当测试业务对象本身时,您无需担心数据库。只需创建对象,可能使用反射设置私有字段,并对对象进行测试即可。
在测试需要与数据访问层交互的代码时,请使用模拟来创建模拟数据层,并设置期望以返回所需的对象或正确响应保存操作。您可能需要将数据层开发为接口(或者如果使用不支持直接模拟的严格框架,则将其包装为可模拟类)。大多数模拟框架要求方法是虚拟的,以允许创建模拟实现。使用接口强制执行类中的方法为虚拟方法,因此模拟更加容易。

谢谢!这听起来不错,但似乎需要做很多工作。我正在使用CSLA框架来处理我的业务对象,不确定如何精确地进行转换。 - mattruma

2

有关使用CSLA进行TDD的更多信息可以在此问题的答案中找到。特别是这个

此外,这个问题可能很有趣。


2

使用依赖注入。在接口中实现数据库方法。然后编写一个新的接口实现,控制数据以测试适用场景。


谢谢!我正在使用CSLA作为我的应用程序框架,但它似乎不太友好于DI。我很想这样做! - mattruma

1
通常我会创建BO,将其保存到fixture setup中的数据库中,然后对各种插入/更新/选择进行测试,最后在teardown中从数据库中删除对象。这样可以保持事情的整洁,特别是当涉及到许多约束时,如果您不删除测试中创建的所有内容,您的测试数据库可能会变得非常混乱。

1

为了测试数据库访问层,您不应该在同一个数据库上运行所有测试。某些测试可能会失败,因为它们依赖于其他测试的结果。所以这不是您想要的。实际上,在每个测试之后,您应该将数据库状态返回到测试运行之前的原始状态。

在我的实践中,我将测试数据集保存在 XML 中,并在每个测试之前使用 XML 在数据库中设置数据。因此,每个测试都针对某个数据集运行。


1

我支持一种说法,即应该使用模拟数据库来测试业务对象。但在某些情况下,您可能希望将数据作为测试的一部分进行持久化。这样做的缺点是测试时间更长,需要进行清理。

解决此问题的一种方法是使用内存数据库进行测试。例如,SQLite允许您动态创建内存数据库,并在处理完它们后将其删除。这使得您的测试速度更快,而且您不必设置清理代码 - 同时您实际上可以通过自动化测试来测试您的SQL / db代码。


0

(我知道你不使用Java,但下面的一般策略完全不依赖于Java)

我正在开发一个使用大量EJB3/JPA代码的Java项目。我决定创建一种模拟容器,能够“部署”EJB并使用内存数据库(HSQL)和Hibernate实体管理器。

这个“容器”在不到1秒钟的时间内启动,并允许我测试大多数业务组件,包括那些通过JPA访问数据库的组件。如果一个服务太复杂而无法支持,那么我就简单地使用EasyMock(或任何其他模拟库)来创建一个虚假的服务,并将其插入到“容器”中。

到目前为止,它已经取得了巨大的成功,但需要我花费几天时间来实现模拟基础设施。


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