补习系列(17)-springboot mongodb 内嵌数据库
简介
前面的文章中,我们介绍了如何在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.5</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 = 27027;
@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=27027
spring.data.mongodb.database=test
D. 启动测试
执行业务测试类,可以看到一系列输出:
//下载
Download PRODUCTION:Windows:B64 START
Download PRODUCTION:Windows:B64 DownloadSize: 147911698
Download PRODUCTION:Windows:B64 0% 1% 2% 3% 4% 5% 6% 7% 8% 9% 10% 11%
...
//启动继承
[mongod output] 2019-03-02T15:43:01.948+0800 I CONTROL [initandlisten] db version v3.2.1
[mongod output] 2019-03-02T15:43:01.948+0800 I CONTROL [initandlisten] git version: a14d55980c2cdc565d4704a7e3ad37e4e535c1b2
[mongod output] 2019-03-02T15:43:01.948+0800 I CONTROL [initandlisten] allocator: tcmalloc
[mongod output] 2019-03-02T15:43:01.948+0800 I CONTROL [initandlisten] modules: none
[mongod output] 2019-03-02T15:43:01.948+0800 I CONTROL [initandlisten] build environment:
[mongod output] 2019-03-02T15:43:01.948+0800 I CONTROL [initandlisten] distmod: 2008plus
[mongod output] 2019-03-02T15:43:01.948+0800 I CONTROL [initandlisten] distarch: x86_64
[mongod output] 2019-03-02T15:43:01.948+0800 I CONTROL [initandlisten] target_arch: x86_64
...
[mongod output] 2019-03-02T15:43:02.070+0800 I NETWORK [initandlisten] waiting for connections on port 27027
//单元测试
...
//关闭进程
[mongod output] 2019-03-02T15:43:20.838+0800 I COMMAND [conn3] terminating, shutdown command received
[mongod output] 2019-03-02T15:43:20.838+0800 I FTDC [conn3] Shutting down full-time diagnostic data capture
[mongod output] 2019-03-02T15:43:20.846+0800 I CONTROL [conn3] now exiting
[mongod output] 2019-03-02T15:43:20.846+0800 I NETWORK [conn3] shutdown: going to close listening sockets...
[mongod output] 2019-03-02T15:43:20.846+0800 I NETWORK [conn3] closing listening socket: 456
[mongod output] 2019-03-02T15:43:20.846+0800 I NETWORK [conn3] shutdown: going to flush diaglog...
[mongod output] 2019-03-02T15:43:20.846+0800 I NETWORK [conn3] shutdown: going to close sockets...
[mongod output] 2019-03-02T15:43:20.911+0800 I NETWORK [conn1] end connection 127.0.0.1:52319 (2 connections now open)
[mongod output] 2019-03-02T15:43:20.911+0800 I STORAGE [conn3] WiredTigerKVEngine shutting down
[mongod output] 2019-03-02T15:43:20.916+0800 I NETWORK [conn2] end connection 127.0.0.1:52320 (1 connection now open)
[mongod output] 2019-03-02T15:43:20.943+0800 I STORAGE [conn3] shutdown: removing fs lock...
[mongod output] 2019-03-02T15:43:20.943+0800 I CONTROL [conn3] dbexit: rc: 0
注:首次使用该组件时需要下载安装包,过程比较缓慢需要些耐心..
细节
细心的同学可能注意到了,我们为什么要特别规避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 == 0) {
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.0</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篇" ,期待更多精彩内容-
补习系列(17)-springboot mongodb 内嵌数据库的更多相关文章
- 补习系列(17)-springboot mongodb 内嵌数据库【华为云技术分享】
目录 简介 一.使用 flapdoodle.embed.mongo A. 引入依赖 B. 准备测试类 C. 完善配置 D. 启动测试 细节 二.使用Fongo A. 引入框架 B. 准备测试类 C.业 ...
- 补习系列(16)-springboot mongodb 数据库应用技巧
目录 一.关于 MongoDB 二.Spring-Data-Mongo 三.整合 MongoDB CRUD A. 引入框架 B. 数据库配置 C. 数据模型 D. 数据操作 E. 自定义操作 四.高级 ...
- SpringBoot内嵌数据库的使用(H2)
配置数据源(DataSource) Java的javax.sql.DataSource接口提供了一个标准的使用数据库连接的方法. 传统做法是, 一个DataSource使用一个URL以及相应的证书去构 ...
- 补习系列(15)-springboot 分布式会话原理
目录 一.背景 二.SpringBoot 分布式会话 三.样例程序 四.原理进阶 A. 序列化 B. 会话代理 C. 数据老化 小结 一.背景 在 补习系列(3)-springboot 几种scope ...
- 补习系列(14)-springboot redis 整合-数据读写
目录 一.简介 二.SpringBoot Redis 读写 A. 引入 spring-data-redis B. 序列化 C. 读写样例 三.方法级缓存 四.连接池 小结 一.简介 在 补习系列(A3 ...
- 补习系列(2)-springboot mime类型处理
目标 了解http常见的mime类型定义: 如何使用springboot 处理json请求及响应: 如何使用springboot 处理 xml请求及响应: http参数的获取及文件上传下载: 如何获得 ...
- H2内嵌数据库的使用
H2内嵌数据库的使用 H2是一个开源的嵌入式数据库引擎,采用java语言编写,不受平台的限制. 同时H2提供了一个十分方便的web控制台用于操作和管理数据库内容. H2还提供兼容模式,可以兼容一些主流 ...
- 补习系列(18)-springboot H2 迷你数据库
目录 关于 H2 一.H2 用作本地数据库 1. 引入依赖: 2. 配置文件 3. 样例数据 二.H2 用于单元测试 1. 依赖包 2. 测试配置 3. 测试代码 小结 关于 H2 H2 数据库是一个 ...
- 补习系列(12)-springboot 与邮件发送【华为云技术分享】
目录 一.邮件协议 关于数据传输 二.SpringBoot 与邮件 A. 添加依赖 B. 配置文件 C. 发送文本邮件 D.发送附件 E. 发送Html邮件 三.CID与图片 参考文档 一.邮件协议 ...
随机推荐
- 为什么说JAVA中要慎重使用继承
JAVA中使用到继承就会有两个无法回避的缺点: 打破了封装性,迫使开发者去了解超类的实现细节,子类和超类耦合. 超类更新后可能会导致错误. 继承打破了封装性 关于这一点,下面是一个详细的例子(来源于E ...
- react-navigation android 导航标题居中
先贴下代码供参考: 安卓默认导航的titile 是在左侧的,为了和iOS保持一致,需要添加 alignSelf:'center',这个 属性 但是会遇到title有点偏右的情况 添加headerRig ...
- 谈谈surging引擎的tcp、http、ws协议和如何容器化部署
1.前言 分布式已经成为了当前最热门的话题,分布式框架也百花齐放,群雄逐鹿.从中心化服务治理框架,到去中心化分布式服务框架,再到分布式微服务引擎,这都是通过技术不断积累改进而形成的结果.esb,网关, ...
- ASP.NET Core 实战:基于 Dapper 扩展你的数据访问方法
一.前言 在非静态页面的项目开发中,必定会涉及到对于数据库的访问,最开始呢,我们使用 Ado.Net,通过编写 SQL 帮助类帮我们实现对于数据库的快速访问,后来,ORM(Object Relatio ...
- 【推荐】 HyperLedger Fabric环境搭建、测试及注意事项 [详尽指导] [亲测有效]
系统:Ubuntu16.04 LTS 一.环境准备 1.1 Ubuntu下安装 crul sudo apt install curl curl是利用URL语法在命令行方式下工作的开源文件传输工具.它被 ...
- java游戏开发杂谈 - java编程怎么学
java语言包含很多的知识点,我们并不需要把java语言的知识点都学全了,才开始编程. 你只需要了解: 1,java的数据类型和变量定义 2,类和对象的初步印象. 3,if-else, wh ...
- centos 修改hostname
centos修改主机名的正确方法 1 centos6下修改hostname [root@centos6 ~]$ hostname # 查看当前的hostnmae centos6.magedu.com ...
- 入门系列之Scikit-learn在Python中构建机器学习分类器
欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~ 本文由信姜缘 发表于云+社区专栏 介绍 机器学习是计算机科学.人工智能和统计学的研究领域.机器学习的重点是训练算法以学习模式并根据数据进行预 ...
- DevOps实践之一:基于Docker构建企业Jenkins CI平台
基于Docker构建企业Jenkins CI平台 一.什么是CI 持续集成(Continuous integration)是一种软件开发实践,每次集成都通过自动化的构建(包括编译,发布,自动化测试)来 ...
- Percona XtraBackup 8.0, 安装与测试
Percona XtraBackup 8.0 是Percona XtraBackup新推出了一个针对MySQL8.0的版本,主要是MySQL8.0在Redo 和 数据库字典方面有了新的改进. Xtra ...