前言

对于测试的重要性,虽然不想说什么漂亮话,但是作为敏捷开发实践的重要一环,以及本着对自己代码负责的理念,在项目中保证必要的单元测试和覆盖率还是非常重要的。

在研究怎么在SpringBoot中优雅的进行单元测试的过程中,主要参考了:

  1. 有赞单元测试实践:主要参考了工具选型的思路和整合的思路。
  2. SpringTest文档
  3. SpringBoot Test文档
  4. SpringBoot 中文翻译文档–测试

在文档中主要参考了MockMvc的使用,关于MockMvc之前也写过blog:翻译:Spring MVC Test Framework–MockMvc使用.在当时主要是尝试了对单个项目的端口测试,在这次研究中主要考虑如何方便的对单个服务中依赖的服务进行打桩(stub)和Mock.

续前言

原本是打算把每个框架的使用方法都写写的,但是在几天的整合实践之后发现官方的文档都很友善所以下面就当作一个内容的小结,把一些需要注意的点总结一下,详细的用法还是看官方文档就可以了.

PowerMock

PowerMock在单测中的应用场景主要是对单测服务所依赖静态类的Mock.

官方的文档地址(主要使用了Mockito接口)

使用方法官方也给出了例子,在静态方法Mock时主要需要@PrepareForTest注解:

1
2
3
4
5
6
7
8
9
10
// 1.类注解@PrepareForTest
@PrepareForTest(Static.class) // Static.class contains static methods
// 2.指定需要mock的静态方法
PowerMockito.mockStatic(Static.class);
// 3.使用Mockito接口来mock
// 在mock返回值为`void`的静态方法时可以使用`PowerMockito`的`when()`来进行mock
Mockito.when(Static.firstStaticMethod(param)).thenReturn(value);
// 4.校验mock结果
PowerMockito.verifyStatic(Static.class); // 1
Static.firstStaticMethod(param); // 2

SpringBoot集成Mock

整合主要参考了有赞单元测试实践中的整合方法,主要是需要整合PowerMock使得能够对静态类进行mock.

由于mock静态方法需要

@PrepareForTest({Static.class})

注解所以需要将UnitRunner指定为PowerMockRunner,而由于需要和Spring整合,则需要SpringRunner,整合结果:

@RunWith(PowerMockRunner.class)

@PowerMockRunnerDelegate(SpringRunner.class)

最终的整合结果为:

1
2
3
4
5
6
7
8
9
10
// powermock
@RunWith(PowerMockRunner.class)
// 整合springtest
@PowerMockRunnerDelegate(SpringRunner.class)
// 排除java.security
@PowerMockIgnore( {"javax.management.*", "javax.net.ssl.*"})
// mock静态类注解
@PrepareForTest(Static.class)
// SpringBoot测试的注解
@SpringBootTest

参照有赞的单元测试基类代码:
image-20200414201352164

SpringBoot自带MockBean

主要基于SpringBoot的文档(发现SpringBoot相关的东西还是得多看官方文档才行)介绍的@MockBean注解.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import org.junit.*;
import org.junit.runner.*;
import org.springframework.beans.factory.annotation.*;
import org.springframework.boot.test.context.*;
import org.springframework.boot.test.mock.mockito.*;
import org.springframework.test.context.junit4.*;

import static org.assertj.core.api.Assertions.*;
import static org.mockito.BDDMockito.*;

@RunWith(SpringRunner.class)
@SpringBootTest
public class MyTests {

@MockBean
private RemoteService remoteService;

@Autowired
private Reverser reverser;

@Test
public void exampleTest() {
// RemoteService has been injected into the reverser bean
given(this.remoteService.someCall()).willReturn("mock");
String reverse = reverser.reverseSomeCall();
assertThat(reverse).isEqualTo("kcom");
}

}

MockMvc

主要是有了一个注解方法来代替之前的手动创建mockMvc的形式,在这里记录一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import org.junit.jupiter.api.Test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

@SpringBootTest
@AutoConfigureMockMvc
class MockMvcExampleTests {

@Test
void exampleTest(@Autowired MockMvc mvc) throws Exception {
mvc.perform(get("/")).andExpect(status().isOk()).andExpect(content().string("Hello World"));
}

}

还有一个@WebMvcTest注解应该等价于之前的mockmvc的standalone启动模式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import org.junit.*;
import org.junit.runner.*;
import org.springframework.beans.factory.annotation.*;
import org.springframework.boot.test.autoconfigure.web.servlet.*;
import org.springframework.boot.test.mock.mockito.*;

import static org.assertj.core.api.Assertions.*;
import static org.mockito.BDDMockito.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@RunWith(SpringRunner.class)
@WebMvcTest(UserVehicleController.class)
public class MyControllerTests {

@Autowired
private MockMvc mvc;

@MockBean
private UserVehicleService userVehicleService;

@Test
public void testExample() throws Exception {
given(this.userVehicleService.getVehicleDetails("sboot"))
.willReturn(new VehicleDetails("Honda", "Civic"));
this.mvc.perform(get("/sboot/vehicle").accept(MediaType.TEXT_PLAIN))
.andExpect(status().isOk()).andExpect(content().string("Honda Civic"));
}

}

Dubbo Service的Mock

// TODO

扩展

easy-random:

Easy Random is a library that generates random Java beans.

在项目中主要用在单测需要复杂的DTO的时候,如果项目中对现有的复杂DTO没用random工具的话还是非常不错的.

开篇

在日趋增长的体重已经不能再被掩盖之后,健身的计划也是需要提上日程了.也是正好发了补助,就打算好了买辆车开始骑行吧.

开启一个新的骑行日志记录,也算是对自己的一个督促,希望能够把这个兴趣坚持下去吧.

10.22 西湖 40km

毕竟是第一次正式”骑行”,虽然之前做了预估但是还是有点超了里程了.而且在灵隐寺上坡的那段路都是上坡路差点就让我放弃开始折返了,但是还好也是坚持了下来,从隧道开始的下坡路的一路加速骑行也是真的非常痛快了.

在骑到之江路的时候以为看到了钱塘江发现并不怎么样还是有点失望的,知道往前面又骑了几km然后发现了一个水坝之后才意识到:这才是钱塘江啊.

脑海里首先跳出来的竟然是观潮练剑的吕钱塘和那个在钱塘江破甲两千六的李淳罡,身体又不由得一凛,但是再看看这夜晚的钱塘江和对面的繁华:杭州真是个神奇的城市 –从山里骑出来的我如此感叹道.

确实,杭州的繁华和他的安静很好的融合在了一起,没有人会诧异西湖的景色和那种反璞入深林的代入感,但灯火通明的城区却也是杭州.

回来的路大致也就是沿着西湖的另一面开始折返回家了.

也是第一次看到了夜晚的雷峰塔:

还有夜晚的长林公园:

唯一的不足就是这开始就进行的40km的跋涉确实有点累,人也是酸了好几天才恢复过来….

10.24 西湖 24km

有了第一次的经验,第二次就理智了很多,总共20km的距离也还算是比较合理吧.主要的调整还是把坐凳调高了很多,发力变得舒服了很多所以速度理论上是要比前一次好一点的.

在杨公堤上也是趁着一个长下坡,把齿比变到最大体验了一下40码的快感(虽然马上就又是一个上坡),但是夜晚的凉风吹拂的速度感,可能就是骑行的乐趣所在吧.

总结

当然,一开始的时候总是很兴奋的.原本一周三次的计划也因为这周末的连续两天阴雨而破灭了,不过周六也算是骑行20km左右加上逛了一下午的西湖,所以也没有什么愧罪感吧.

之后也会尝试新的路线和给自己提高要求,当然那都是后话了.在博客完结的时候劝勉自己这只是漫漫长路的开始吧.

雄关漫道真如铁,而今迈步从头越。
从头越,
苍山如海,残阳如血。

(很想着《赘婿》,突然就想起了上面这几句)

写在前面

之前也是写了一篇这周搞的一些新东西,其实当时就是看了V2站长开始写周报也有了点想法但是想想似乎每周也没有那么多可写的内容,就先随便写了一篇.但是最近也算是有点清闲又骚了很多新的东西就不免想要记录一下,正好趁着给博客重新进行了一波整理分类之后也是下了开始写周报的决心吧,但是频率可能也就是2周或者3周记录和总结一下.

ps. 目前格式就按照事情来排列然后加以描述

v2ray

在经历了一系列不可描述的会议之后,在2个星期前我的hk服务器算是终于又通了$$了,但是鉴于封杀时的效率还是有点怕自己的ip被封了的,所以就趁着摸鱼的时光研究了一下v2ray.当然不是深入研究,最开始是找了一个一键部署的脚本,也就是填一下配置就能直接用了感觉还是很不错的.

V2Ray一键安装脚本

HTTP/2

在后来看了这个v2ray-HTTP/2之后发现HTTP/2似乎是很”香”就打算尝试一下,但是:

与其它的传输层协议一样在 streamSettings 中配置,不过要注意的是使用 HTTP/2 要开启 TLS。

似乎是要上HTTPS了,鉴于现在的域名还用在博客上就又重新申请了一个域名用来申请一个免费的HTTPS证书然后用来配置HTTP/2.

CDN

Cloudflare 还是太慢了,用国内的吧,绝对能体验飞一般的速度,正好 V2Ray 已经支持 HTTP/2 了,又拍云、七牛、阿里都不错,腾讯的 h2 还在内测,百度不清楚。不过说真的,CDN 的话国外的还是有些水土不服,强烈建议使用国内的,速度提升非常大,也非常稳定,高峰期毫无压力,在重点 IP 段也无所畏惧。

就是跟着上面的HTTP/2又顺势看了CDN,想的是如果能使用国内CDN的话岂不是速度能快的飞起(毕竟现在延迟有200ms左右),但是在看了国内免费CDN对比与申请部署教程之后尝试了一下又拍云才发现:国内的备案太痛苦了!!!.并且阿里云的备案要求购买轻量应用服务器续费3个月以上,但是在我续费之后仍然不能申请备案服务号也就放弃了,还是选择了cloudflare.

v2-ui

是在看拯救被墙的IP,CDN + v2ray,安全的科学上网方法这篇博客的时候发现的,发现比一键部署脚本还是挺不错的毕竟有GUI可以用来动态配置.

现在的v2ray配置

大致的流程:

  1. 使用cloudflare来解析域名(修改DNS)
  2. 添加一个A解析指向v2ray的ip,Name自己填写,我使用了www
  3. 在SSL/TLS选项卡中选择Full(Encrypts end-to-end, using a self signed certificate on the server)
  4. 在v2-ui中新建一个账号,端口使用了80(玄学:因为大部分网站都使用80端口做web服务所以不容易被侦测),配置http(就是http/2),host和域名都填了上面解析的域名,然后选择申请的免费ssl证书
  5. 导出配置

下面是我的配置截图:
HTTP/2+TLS

Aria2+Filebrowser

有了服务器就会开始折腾,因为自己电脑挂bt有点慢而且AMD出名的功耗高也不想因为下个视频就一直开着于是就想到在服务器上在整一个Aria来挂bt然后再来一个远程播放岂不美哉?

当然有轮子是最好的,于是就找到了:使用Docker安装Aria2+AriaNg+Filebrowser,可离线BT下载/在线播放,直接docker run 非常不错:

1
docker run --name ccaa -d -p 6800:6800 -p 6080:6080 -v /home/root/aria-download:/Down moerats/ccaa:latest

当然-v不是必要的,这是为了后面做铺垫

NextCloud

Nextcloud是一套用于创建网络硬盘的客户端-服务器软件。其功能与Dropbox相近,但Nextcloud是自由及开放源代码软件,每个人都可以在私人服务器上安装并运行它。

与Dropbox等专有服务相比,Nextcloud的开放架构让用户可以利用应用程序的方式在服务器上新增额外的功能,并让用户可以完全掌控自己的数据。
Nextcloud的文件存储在一般的目录结构中,并可透过WebDAV访问。用户的文件会在传输时加密。Nextcloud可与在Windows(Windows XP、Vista、7与8)、macOS(10.6或更新版本)或是多种Linux散布版上运行的客户端同步。

Nextcloud用户可以管理日历(使用CalDAV)、联系人(CardDAV)、计划工作与流媒体(Ampache)。

从管理的角度来看,Nextcloud允许用户与组群管理(透过OpenID或LDAP)。透过用户间与/或组群间的读/写权限调整达到分享文件的目的。另外,Nextcloud的用户可以创建公开的URL来分享文件。也可以记录与文件相关的动作,以及利用文件访问规则来禁止对特定文件的访问[2]。

此外,用户也可以透过浏览器使用Nextcloud的文本编辑器、书签服务、缩略网址服务、相册、RSS阅读器与文件查看器。因为有良好的扩展性,Nextcloud可以透过鼠标点一下即可完成安装的应用程序强化其功能,并可连线至Dropbox、Google云端硬盘与Amazon S3。 ————来自维基百科

上面的-v当然是这里用到了,原因是有些视频格式对于Filebrowser来说太难了,并不能正确的解析,在线观看也就无从说起了.所以在一番调研之后决定在为了能看视频的同时顺便尝试一下这私人网盘是什么感觉的.

当然还是方便的docker部署了:

1
docker run -d --restart=always --name nextcloud -p 8888:80 -v /root/nextcloud:/data -v /home/root/aria-download:/aria docker.io/nextcloud

然后在NextCloud挂载外部存储就可以了.

JetBrains 免费License

在毕业几个月之后终于意识到:我的学生邮箱没了,也就是说不能再白嫖好用的idea了(才怪),在琢磨了一番之后发现了官方的面向开发者的免费许可:Open Source License Request,于是就用这个博客项目尝试了一波,一开始也是没有抱多大希望的,毕竟项目没人star也没人fork,但是在几天之后收到了:

于是就快乐的激活了许可:

虽然感觉还是受之有愧,但是毕竟JB对开发者这么好也就只能收下这份许可来继续激励我写博客吧.

咖啡

不知道是什么时候养成的习惯吧,但是现在似乎是已经离不开咖啡了,之前的出租房地方比较小的时候还是喝一喝挂耳咖啡,在这次搬家之后也是空间Dark♂了很多然后就趁着双11入了一个法压壶+咖啡豆,一是挂耳确实有点贵,买咖啡豆的话买些意式拼配的豆子也是比挂耳便宜了许多,再者也是想尝试一下是不是法压壶能够提升一下鉴赏咖啡的水平.

在尝试了两次之后发现还是挺不错的,也是开始进行变量控制来尝试自己最喜欢的配比跟步骤吧:

博客分类

空闲的时候重新回来看了看博客的分类着实有些杂乱,后面打算写文章也不知道往哪里分比较好就重构了一下自己博客的分类方式,现在也算是比较满意了吧(最起码新写博客的时候不再为了这个分类头疼了).

骑行

鉴于不断增加的体重和国庆回家期间被家里人的不断叮嘱,还是觉得要增加一下运动量的嘛,正好拿到了人才补助的钱就想着整了一辆自行车,一来可以代步二来附近也没什么可以跑步的场地正好尝试一下骑行的快乐⑧.

若饭

这是之前看小众软件的时候被推荐了一波,结合上面打算运动一下减减肥的理念,也就尝试了一下新手套餐发现液体的饮料还是比较能接受的(喝上去感觉和豆奶很像),就整了一罐粉末来当晚饭.个人感觉还是可以接受的,饱腹感也还可以.就先体验一下,说不定也会有回购和体验的测评.

总结

周报周报,可能对我来说更像是多了一个文字输出的渠道吧,毕竟网络社交渠道基本都已经是断绝了,有一个输出口也不见得是一件坏事.

当然有时候似乎很坚信自己现在清晰的知道自己究竟想要什么,在做什么,但是有时在陌生的边缘徘徊的时候又觉得自己似乎几年来还是一个dio样子又不免让人觉得蕉躁.

当然,多想多看,多写写日志吧.

吾尝终日而思矣 不如须臾之所学也

0%