wul*_*pro 61 java junit unit-testing mongodb morphia
我选择的数据库是MongoDB.我正在编写一个数据层API来从客户端应用程序中抽象实现细节 - 也就是说,我实际上提供了一个单独的公共接口(一个充当IDL的对象).
我正在以TDD的方式测试我的逻辑.在每个单元测试之前,@Before调用一个方法来创建数据库单例,之后,当测试完成时,@After调用一个方法来删除数据库.这有助于提高单元测试之间的独立性.
几乎所有的单元测试,即执行上下文查询,都需要事先发生某种插入逻辑.我的公共接口提供了一个插入方法 - 然而,使用此方法作为每个单元测试的前驱逻辑似乎是不正确的.
我真的需要某种模拟机制,但是,我对模拟框架没有多少经验,而且Google似乎没有返回任何可能与MongoDB一起使用的模拟框架.
其他人在这些情况下做了什么?也就是说,人们如何单元测试与数据库交互的代码?
此外,我的公共接口连接到外部配置文件中定义的数据库 - 使用此连接进行单元测试似乎不正确 - 再次,这种情况会受益于某种类型的模拟?
sbr*_*ges 62
技术上与数据库(nosql或其他)通信的测试不是单元测试,因为测试正在测试与外部系统的交互,而不仅仅是测试隔离的代码单元.然而,与数据库通信的测试通常非常有用,并且通常足够快以与其他单元测试一起运行.
通常我有一个Service接口(例如UserService),它封装了处理数据库的所有逻辑.依赖于UserService的代码可以使用模拟版本的UserService并且易于测试.
在测试与Mongo(例如MongoUserService)对话的服务的实现时,最简单的方法是编写一些java代码来启动/停止本地机器上的mongo进程,让你的MongoUserService连接到那个,看看这个问题是否有些问题.笔记.
您可以尝试在测试MongoUserService时模拟数据库的功能,但通常这很容易出错,并且不会测试您真正想要测试的内容,即与真实数据库的交互.因此,在为MongoUserService编写测试时,您需要为每个测试设置数据库状态.查看DbUnit以获取使用数据库执行此操作的框架示例.
rit*_*rit 30
正如sbridges在这篇文章中所写,不要有专门的服务(有时也称为存储库或DAO)从逻辑中抽象出数据访问是一个坏主意.然后你可以通过提供DAO的模拟来测试逻辑.
我做的另一种方法是创建一个Mongo对象的模拟(例如PowerMockito),然后返回适当的结果.这是因为您不必测试数据库是否在单元测试中工作,但是您应该测试是否将正确的查询发送到数据库.
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));
Run Code Online (Sandbox Code Playgroud)
这也是一种选择.当然,模拟的创建和相应对象的返回仅作为上面的例子编码.
Ben*_*gel 17
我在Java中编写了一个MongoDB伪实现:mongo-java-server
默认值是内存后端,可以在单元和集成测试中轻松使用.
MongoServer server = new MongoServer(new MemoryBackend());
// bind on a random local port
InetSocketAddress serverAddress = server.bind();
MongoClient client = new MongoClient(new ServerAddress(serverAddress));
DBCollection coll = client.getDB("testdb").getCollection("testcoll");
// creates the database and collection in memory and inserts the object
coll.insert(new BasicDBObject("key", "value"));
assertEquals(1, collection.count());
assertEquals("value", collection.findOne().get("key"));
client.close();
server.shutdownNow();
Run Code Online (Sandbox Code Playgroud)
今天,我认为最佳实践是在Python上使用testcontainers库(Java)或testcontainers-python端口。它允许将Docker映像与单元测试一起使用。要在Java代码中运行容器,只需实例化GenericContainer对象(例如):
GenericContainer mongo = new GenericContainer("mongo:latest")
.withExposedPorts(27017);
MongoClient mongoClient = new MongoClient(mongo.getContainerIpAddress(), mongo.getMappedPort(27017));
MongoDatabase database = mongoClient.getDatabase("test");
MongoCollection<Document> collection = database.getCollection("testCollection");
Document doc = new Document("name", "foo")
.append("value", 1);
collection.insertOne(doc);
Document doc2 = collection.find(new Document("name", "foo")).first();
assertEquals("A record can be inserted into and retrieved from MongoDB", 1, doc2.get("value"));
Run Code Online (Sandbox Code Playgroud)
或在Python上(例如):
mongo = GenericContainer('mongo:latest')
mongo.with_bind_ports(27017, 27017)
with mongo_container:
def connect():
return MongoClient("mongodb://{}:{}".format(mongo.get_container_host_ip(),
mongo.get_exposed_port(27017)))
db = wait_for(connect).primer
result = db.restaurants.insert_one(
# JSON as dict object
)
cursor = db.restaurants.find({"field": "value"})
for document in cursor:
print(document)
Run Code Online (Sandbox Code Playgroud)