使用 MongoDB 进行单元测试

2022-08-31 13:09:48

我选择的数据库是MongoDB。我正在编写一个数据层API来抽象客户端应用程序中的实现细节 - 也就是说,我基本上提供了一个公共接口(一个充当IDL的对象)。

我正在以TDD的方式测试我的逻辑。在每个单元测试之前,调用一个方法来创建数据库单一实例,之后,当测试完成时,将调用一个方法来删除数据库。这有助于促进单元测试之间的独立性。@Before@After

几乎所有的单元测试(即执行上下文查询)都需要在手头之前进行某种插入逻辑。我的公共接口提供了一个插入方法 - 但是,将此方法用作每个单元测试的前导逻辑似乎不正确。

实际上,我需要某种模拟机制,但是,我对模拟框架没有太多经验,而且Google似乎没有返回任何可能与MongoDB一起使用的模拟框架。

在这些情况下,其他人会怎么做?也就是说,人们如何单元测试与数据库交互的代码?

此外,我的公共接口连接到外部配置文件中定义的数据库 - 将此连接用于我的单元测试似乎不正确 - 再次,这种情况会从某种模拟中受益吗?


答案 1

从技术上讲,与数据库(nosql或其他)通信的测试不是单元测试,因为测试是测试与外部系统的交互,而不仅仅是测试一个独立的代码单元。但是,与数据库通信的测试通常非常有用,并且通常足够快,可以与其他单元测试一起运行。

通常我有一个服务接口(例如UserService),它封装了处理数据库的所有逻辑。依赖于 UserService 的代码可以使用 UserService 的模拟版本,并且很容易测试。

在测试与Mongo通信的服务实现(例如MongoUserService)时,最简单的方法是编写一些java代码,这些代码将在本地计算机上启动/停止mongo进程,并让您的MongoUserService连接到该进程,请参阅此问题以获取一些注释

你可以在测试MongoUserService时尝试模拟数据库的功能,但通常这太容易出错,并且不会测试你真正想要测试的内容,即与真实数据库的交互。因此,在为MongoUserService编写测试时,您需要为每个测试设置一个数据库状态。查看 DbUnit,了解使用数据库执行此操作的框架示例。


答案 2

正如 sbridges 在这篇文章中所写的那样,没有一个专门的服务(有时也称为存储库或 DAO)来从逻辑中抽象出数据访问是一个坏主意。然后,您可以通过提供 DAO 的模拟来测试逻辑。

我做的另一种方法是创建Mongo对象的Mock(例如PowerMockito),然后返回适当的结果。这是因为您不必测试数据库是否在单元测试中工作,而更应该测试是否正确的查询已发送到 databse。

Mongo mongo = PowerMockito.mock(Mongo.class);
DB db = PowerMockito.mock(DB.class);
DBCollection dbCollection = PowerMockito.mock(DBCollection.class);

PowerMockito.when(mongo.getDB("foo")).thenReturn(db);
PowerMockito.when(db.getCollection("bar")).thenReturn(dbCollection);

MyService svc = new MyService(mongo); // Use some kind of dependency injection
svc.getObjectById(1);

PowerMockito.verify(dbCollection).findOne(new BasicDBObject("_id", 1));

这也是一种选择。当然,模拟的创建和相应对象的返回只是作为上面的示例进行编码。


推荐