目录

简介

前面的文章中,我们介绍了如何在SpringBoot 中使用MongoDB的一些常用技巧。
那么,与使用其他数据库如 MySQL 一样,我们应该怎么来做MongoDB的单元测试呢?

使用内嵌数据库的好处是不需要依赖于一个外部环境,如果每一次跑单元测试都需要依赖一个稳定的外部环境,那么这样的测试是极不稳定的。
为了更欢快的使用MongoDB,这里提供两种使用内嵌数据库做单元测试的方式。

一、使用 flapdoodle.embed.mongo

开源地址
该组件的大致原理是,在当前环境中自动下载MongoDB并拉起进程,测试后再做关闭。
先演示一遍如何使用:

A. 引入依赖

         <dependency>
<groupId>de.flapdoodle.embed</groupId>
<artifactId>de.flapdoodle.embed.mongo</artifactId>
<version>1.50.</version>
<scope>test</scope>
</dependency>

B. 准备测试类

编写一个基础类:

 @RunWith(SpringRunner.class)
@SpringBootTest(classes = DemoBoot.class)
@ActiveProfiles("test")
public class BaseEmbededMongoTest { private static final Logger logger = LoggerFactory.getLogger(BaseEmbededMongoTest.class);
protected static final MongodStarter starter = MongodStarter.getDefaultInstance();
protected static MongodExecutable _mongodExe;
protected static MongodProcess _mongod; // 确保与配置一致
protected static final String host = "127.0.0.1";
protected static final int port = ; @BeforeClass
public static void setUp() throws Exception {
_mongodExe = starter.prepare(new MongodConfigBuilder().version(Version.Main.PRODUCTION)
.net(new Net(host, port, Network.localhostIsIPv6())).build());
_mongod = _mongodExe.start(); logger.info("mongod started on {}:{}", host, port);
} @AfterClass
public static void tearDown() throws Exception {
_mongod.stop();
_mongodExe.stop();
}
}

BaseEmbededMongoTest 实现了:

  • 测试启动前启动MongoDB进程;
  • 测试完成后关闭MongoDB进程;

让业务测试类继承于基础类:

 public class BookServiceTest extends BaseEmbededMongoTest{

     @Autowired
private BookService bookService; @Autowired
private BookRepository bookRepository;
...

C. 完善配置

为了避免冲突,需要关闭EmbeddedMongoAutoConfiguration

 @SpringBootApplication
@EnableAutoConfiguration(exclude = { EmbeddedMongoAutoConfiguration.class})
public class BootSampleMongo {
...

最后一步,为了让业务代码能连接到自启动的MongoDB,需要做对应的配置:

在src/test/resources目录中编辑 application-test.properties

 spring.data.mongodb.host=localhost
spring.data.mongodb.port=
spring.data.mongodb.database=test

D. 启动测试

执行业务测试类,可以看到一系列输出:

 //下载
Download PRODUCTION:Windows:B64 START
Download PRODUCTION:Windows:B64 DownloadSize:
Download PRODUCTION:Windows:B64 % % % % % % % % % % % %
...
//启动继承
[mongod output] --02T15::01.948+ I CONTROL [initandlisten] db version v3.2.1
[mongod output] --02T15::01.948+ I CONTROL [initandlisten] git version: a14d55980c2cdc565d4704a7e3ad37e4e535c1b2
[mongod output] --02T15::01.948+ I CONTROL [initandlisten] allocator: tcmalloc
[mongod output] --02T15::01.948+ I CONTROL [initandlisten] modules: none
[mongod output] --02T15::01.948+ I CONTROL [initandlisten] build environment:
[mongod output] --02T15::01.948+ I CONTROL [initandlisten] distmod: 2008plus
[mongod output] --02T15::01.948+ I CONTROL [initandlisten] distarch: x86_64
[mongod output] --02T15::01.948+ I CONTROL [initandlisten] target_arch: x86_64
...
[mongod output] --02T15::02.070+ I NETWORK [initandlisten] waiting for connections on port
//单元测试
...
//关闭进程
[mongod output] --02T15::20.838+ I COMMAND [conn3] terminating, shutdown command received
[mongod output] --02T15::20.838+ I FTDC [conn3] Shutting down full-time diagnostic data capture
[mongod output] --02T15::20.846+ I CONTROL [conn3] now exiting
[mongod output] --02T15::20.846+ I NETWORK [conn3] shutdown: going to close listening sockets...
[mongod output] --02T15::20.846+ I NETWORK [conn3] closing listening socket:
[mongod output] --02T15::20.846+ I NETWORK [conn3] shutdown: going to flush diaglog...
[mongod output] --02T15::20.846+ I NETWORK [conn3] shutdown: going to close sockets...
[mongod output] --02T15::20.911+ I NETWORK [conn1] end connection 127.0.0.1: ( connections now open)
[mongod output] --02T15::20.911+ I STORAGE [conn3] WiredTigerKVEngine shutting down
[mongod output] --02T15::20.916+ I NETWORK [conn2] end connection 127.0.0.1: ( connection now open)
[mongod output] --02T15::20.943+ I STORAGE [conn3] shutdown: removing fs lock...
[mongod output] --02T15::20.943+ I CONTROL [conn3] dbexit: rc:

注:首次使用该组件时需要下载安装包,过程比较缓慢需要些耐心..

细节

细心的同学可能注意到了,我们为什么要特别规避EmbeddedMongoAutoConfiguration这个类呢?

在SpringBoot 官方文档中提到了 EmbeddedMongoAutoConfiguration,其作用主要是:

  • 自动检测 flapdoodle.embed.mongo组件是否被引入;
  • 如果当前的运行环境中能找到组件,则会自动启动组件,并在程序退出时做销毁

我们简单看一下其实现:

 @Configuration
@EnableConfigurationProperties({ MongoProperties.class, EmbeddedMongoProperties.class })
@AutoConfigureBefore(MongoAutoConfiguration.class)
@ConditionalOnClass({ Mongo.class, MongodStarter.class })
public class EmbeddedMongoAutoConfiguration {
private final MongoProperties properties;
private final EmbeddedMongoProperties embeddedProperties; @Bean(initMethod = "start", destroyMethod = "stop")
@ConditionalOnMissingBean
public MongodExecutable embeddedMongoServer(IMongodConfig mongodConfig)
throws IOException {
Integer configuredPort = this.properties.getPort();
if (configuredPort == null || configuredPort == ) {
setEmbeddedPort(mongodConfig.net().getPort());
}
MongodStarter mongodStarter = getMongodStarter(this.runtimeConfig);
return mongodStarter.prepare(mongodConfig);
}

不难猜到,该配置类已经完成了我们在单元测试中所需要的一切事情,那为什么还需要BaseEmbededMongoTest?
答案在于,我们可能会对MongoDB的连接池做许多定制,如下面的代码:

 @Configuration
public void MongoConfig{
@Bean
public MongoDbFactory mongoDbFactory(){
...
}
}

类似这样的定制,会让MongoAutoConfiguration失效。即SpringDataMongo 的初始化会先于Embeded实例的启动,导致失败。
通过自定义的实现则可以规避该问题,当然如果通过Profile设定也可以进行规避。

二、使用Fongo

开源地址
Fongo 是由 Fousquare 开发团队开源的一款真正的内存式MongoDB,非常适用于轻量级的单元测试。
这个名字.. 不错哈

Fongo 支持对Java-Driver的各种CRUD指令进行解析,并模拟数据在内存中的存储管理操作,可以认为其提供了一层JavaDriver的代理。
同时,该框架是线程安全的,所有的集合读写操作都能得到同步保护

接下来是如何使用:

A. 引入框架

 <!-- fongo face mongo -->
<dependency>
<groupId>com.github.fakemongo</groupId>
<artifactId>fongo</artifactId>
<version>2.1.</version>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</exclusion>
<exclusion>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</exclusion>
</exclusions>
</dependency>

注:fongo依赖于jackson,可能与SpringBoot项目冲突,这里显示将其剔除。

B. 准备测试类

编写一个基于Fongo的类:

 @ActiveProfiles("test")
@RunWith(SpringRunner.class)
@SpringBootTest(classes = BootSampleMongo.class)
@Import(TestConfig.class)
public class BaseFongoTest { }

这里使用@Import导入了一个TestConfig,用于初始化Fongo实例,如下:

 @TestConfiguration
@Profile("test")
public class TestConfig extends AbstractMongoConfiguration { @Autowired
private Environment env; @Override
protected String getDatabaseName() {
return env.getProperty("spring.data.mongodb.database", "test");
} @Override
public Mongo mongo() throws Exception {
return new Fongo(getDatabaseName()).getMongo();
} }

这样,通过继承于AbstractMongoConfiguration,可以省去配置MongoDbFactory之类的工作。
需要注意的是,如果业务代码做了一些连接池的定制,如MongoDbFactory/MongoTemplate的定义,则需要通过Profile进行隔离,避免在测试过程中出错:

 @Configuration
@Profile("prod")
public class ProdMongoConfig {
...

C.业务测试

准备好上面的工作后,则可以用到业务测试代码上:

 public class BookServiceTest extends BaseFongoTest{

     @Autowired
private BookService bookService; @Autowired
private BookRepository bookRepository;

至此,我们已经完成了Fongo 的使用。

码云同步代码

参考文档

springboot-with-mongo-embed
flapdoodle-embed-mongo-github
another-embededmongo-fongo

小结

随着MongoDB 在Web开发中的应用越来越广,许多配套的框架及工具也在逐步完善。
本文介绍了两种在SpringBoot 框架上使用内嵌MongoDB的方式,从简易性来看,个人更推荐Fongo的方案。
由于Fongo 更接近于H2(一种内存SQL数据库)的实现,整个测试过程中不需要开启MongoDB进程,也免去了远程下载软件的烦恼。
所有的操作均在内存中完成,会令整个测试更加的高效,然而其仅有的缺点是无法支持一些原生的MongoDB管理命令(一般也不会用到)。
当然,读者也可以根据自己的需求自行选择。

欢迎继续关注"美码师的补习系列-springboot篇" ,期待更多精彩内容^-^

作者:美码师

HDC.Cloud 华为开发者大会2020 即将于2020年2月11日-12日在深圳举办,是一线开发者学习实践鲲鹏通用计算、昇腾AI计算、数据库、区块链、云原生、5G等ICT开放能力的最佳舞台。

欢迎报名参会

补习系列(17)-springboot mongodb 内嵌数据库【华为云技术分享】的更多相关文章

  1. 补习系列(17)-springboot mongodb 内嵌数据库

    目录 简介 一.使用 flapdoodle.embed.mongo A. 引入依赖 B. 准备测试类 C. 完善配置 D. 启动测试 细节 二.使用Fongo A. 引入框架 B. 准备测试类 C.业 ...

  2. 补习系列(12)-springboot 与邮件发送【华为云技术分享】

    目录 一.邮件协议 关于数据传输 二.SpringBoot 与邮件 A. 添加依赖 B. 配置文件 C. 发送文本邮件 D.发送附件 E. 发送Html邮件 三.CID与图片 参考文档 一.邮件协议 ...

  3. 补习系列(16)-springboot mongodb 数据库应用技巧

    目录 一.关于 MongoDB 二.Spring-Data-Mongo 三.整合 MongoDB CRUD A. 引入框架 B. 数据库配置 C. 数据模型 D. 数据操作 E. 自定义操作 四.高级 ...

  4. 【华为云技术分享】MongoDB经典故障系列五:sharding集群执行sh.stopBalancer()命令被卡住怎么办?

    [摘要] MongoDB sharding集群执行sh.stopBalancer()命令时被卡住怎么办?别慌,华为云数据库来给您支招,收下这份方案指南,让您分分钟远离被自建MongoDB数据库支配的恐 ...

  5. MongoDB 谨防索引seek的效率问题【华为云技术分享】

    目录 背景 初步分析 索引seeks的原因 优化思路 小结 声明:本文同步发表于 MongoDB 中文社区,传送门:http://www.mongoing.com/archives/27310 背景 ...

  6. MySQL数据库开发的36条原则【华为云技术分享】

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/devcloud/article/detai ...

  7. 了解 MongoDB 看这一篇就够了【华为云技术分享】

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/devcloud/article/detai ...

  8. 带着canvas去流浪系列之九 粒子动画【华为云技术分享】

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/devcloud/article/detai ...

  9. 带着canvas去流浪系列之八 碰撞【华为云技术分享】

    [摘要] canvas动画-碰撞仿真 示例代码托管在:http://www.github.com/dashnowords/blogs 经过前面章节相对枯燥的练习,相信你已经能够上手canvas的原生A ...

随机推荐

  1. java 使用tess4j实现OCR的最简单样例

    网上很多教程没有介绍清楚tessdata的位置,以及怎么配置,并且对中文库的描述也存在问题,这里介绍一个最简单的样例. 1.使用maven,直接引入依赖,确保你的工程JDK是1.8以上 <dep ...

  2. Quality Center安装步骤

     测试管理工具 u 安装条件: Quality Center:QC9中文版 数据库:Oracle10 g 操作系统:Windows XP u 安装步骤: 1. 点击setup.exe,出现如下界面,点 ...

  3. scrapy-redis 0.6.8 配置信息

    很多博客的db参数配置都不能用,所以记录一下该版本可用的配置 #启用Redis调度存储请求队列 SCHEDULER = "scrapy_redis.scheduler.Scheduler&q ...

  4. shell中sort用法

    1 sort的工作原理 sort将文件的每一行作为一个单位,相互比较,比较原则是从首字符向后,依次按ASCII码值进行比较,最后将他们按升序输出. [rocrocket@rocrocket progr ...

  5. Nginx应用详解及配置

    一.Nginx简介 概述:Nginx是一款由俄罗斯开发的开源的高性能HTTP服务器和反向代理服务器,同时支持IMAP/POP3/SMTP代理服务,其性能优势着为显著,官网上称:单台nginx服务器可以 ...

  6. java.util.ConcurrentModificationException异常;java.util.ConcurrentModificationException实战

    写代码遇到这个问题,很多博客文章都是在反复的强调理论,而没有对应的实例,所以这里从实例出发,后研究理论: 一.错误产生情况 1 .字符型 (1)添加 public static void main(S ...

  7. mybatis框架,使用foreach实现复杂结果的查询--循环List集合方式

    需求,根据用户角色列表  查询用户列表信息 之前我们传入的参数是Array,一个数组的形式,现在我们传入的是一个List集合,其他条件没有变化. /** * 需求:传入指定的用户角色,用户角色有1-n ...

  8. [Algorithm] 118. Pascal's Triangle

    Given a non-negative integer numRows, generate the first numRows of Pascal's triangle. In Pascal's t ...

  9. git crate&query&delete tag(九)

    root@vmuer-VirtualBox:/opt/myProject# git log --pretty=oneline0169b7a1c4bccb47e76711f353fd8d3864bde9 ...

  10. .NET基础知识(02)-拆箱与装箱

    装箱和拆箱几乎是所有面试题中必考之一,看上去简单,就往往容易被忽视.其实它一点都不简单的,一个简单的问题也可以从多个层次来解读. 常见面试题目: 1.什么是拆箱和装箱? 2.什么是箱子? 3.箱子放在 ...