目录

  • 简介
  • 一、使用 flapdoodle.embed.mongo
    • A. 引入依赖
    • B. 准备测试类
    • C. 完善配置
    • D. 启动测试
    • 细节
  • 二、使用Fongo
    • A. 引入框架
    • B. 准备测试类
    • C.业务测试
  • 参考文档
  • 小结

简介

前面的文章中,我们介绍了如何在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;@BeforeClasspublic 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);}@AfterClasspublic static void tearDown() throws Exception {_mongod.stop();_mongodExe.stop();}
}

BaseEmbededMongoTest 实现了:

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

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

public class BookServiceTest extends BaseEmbededMongoTest{@Autowiredprivate BookService bookService;@Autowiredprivate 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")@ConditionalOnMissingBeanpublic 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{@Beanpublic 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 {@Autowiredprivate Environment env;@Overrideprotected String getDatabaseName() {return env.getProperty("spring.data.mongodb.database", "test");}@Overridepublic 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{@Autowiredprivate BookService bookService;@Autowiredprivate 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 内嵌数据库相关推荐

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

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

  2. 补习系列(15)-springboot 分布式会话原理

    目录 一.背景 二.SpringBoot 分布式会话 三.样例程序 四.原理进阶 A. 序列化 B. 会话代理 C. 数据老化 小结 一.背景 在 补习系列(3)-springboot 几种scope ...

  3. MongoDB内嵌文档查询

    MongoDB内嵌文档查询 示例数据结构 [{"name": "lisa", "age": 17,"friends": ...

  4. 补习系列(14)-springboot redis 整合-数据读写

    目录 一.简介 二.SpringBoot Redis 读写 A. 引入 spring-data-redis B. 序列化 C. 读写样例 三.方法级缓存 四.连接池 小结 一.简介 在 补习系列(A3 ...

  5. 补习系列(2)-springboot mime类型处理

    目标 了解http常见的mime类型定义: 如何使用springboot 处理json请求及响应: 如何使用springboot 处理 xml请求及响应: http参数的获取及文件上传下载: 如何获得 ...

  6. 记一次定位解决SpringBoot中内嵌Tomcat的Bug问题

    你知道的越多,不知道的就越多,业余的像一棵小草! 你来,我们一起精进!你不来,我和你的竞争对手一起精进! 编辑:业余草 segmentfault.com/a/1190000038760707 推荐:h ...

  7. H2内嵌数据库的使用

    H2内嵌数据库的使用 H2是一个开源的嵌入式数据库引擎,采用java语言编写,不受平台的限制. 同时H2提供了一个十分方便的web控制台用于操作和管理数据库内容. H2还提供兼容模式,可以兼容一些主流 ...

  8. spring mongodb内嵌文档查询

    spring mongodb内嵌文档查询 代码示例 简化写法 spring mongodb内嵌文档查询示例. {"name": "zsParent", &quo ...

  9. mongodb内嵌数组倒序和分页实现

    mongodb内嵌数组倒序和分页查询实现 目标是对一个document下的某个数组进行倒序分页查询,数据如 {"_id": 1,"items": [1, 2, ...

最新文章

  1. AI时代,为何机器人公司无法盈利只能走向倒闭?
  2. linux中查看lvm的名称,关于Linux中LVM的使用总结
  3. 企业网站建设中seo不能缺
  4. java多态性详解——父类引用子类对象
  5. IntelliJ IDEA 单行注释调整
  6. BZOJ 2763: [JLOI2011]飞行路线 【SPFA】
  7. python 生成器 generator
  8. 18.Linux/Unix 系统编程手册(上) -- 目录与链接
  9. Caffe傻瓜系列(7):solver优化方法
  10. nvidia驱动缓存能清理吗?
  11. 最小生成树算法 | Kruskal’s Minimum Spanning Tree Algorithm
  12. 8421码、5421码、2421码及余三码
  13. int和long类型取值范围。 基本数据类型 byte , short , char ,int , long , float ,double,boolean类型取值范围
  14. 手动在电脑桌面制作关机/重启图标并添加到任务栏
  15. MATLAB实现已知DH参数的正运动方程求解
  16. 【BZOJ1455】罗马游戏(左偏树)
  17. 新高考没有选物理可以学计算机专业吗,高考选科是不是物理特别重要?新高考没有选物理是不是完了?...
  18. RPC原理(1)之深入RPC原理简介
  19. sqlchemy 普通索引和唯一索引
  20. RF02 控制流语法——IF和For语句语法

热门文章

  1. CAN笔记(12) 同步
  2. php限制只能中文,php如何实现一个账号只能有一个人登录
  3. java 代码配置 网络调试助手_java源码:网络调试助手
  4. switch off c语言,逆向工程 | C 语言之 switch-case 分支
  5. linux 运行段错误,在linux下代码运行出现段错误,求大神
  6. 好947 Mybatis 配置resultMap 带參数查询Map 注意selectOne数据库返回结果一条数据库 否则会报错...
  7. 前端学习之路之CSS (一)
  8. HDU2159 FATE(二维背包、带限制条件的背包问题)
  9. ToDictionary
  10. 再见了亲爱的学生们,再见了敬爱的同事们,再见了信狮