单元测试

软件测试分为单元测试、集成测试、功能测试、系统测试。

单元测试

测试某个功能正确性,通常情况一个功能模块会关联多个其他功能模块,这时模拟对象就有用,可以模拟其他模块特定操作行为

被测系统(SUT)

测试替身(Test Double)

减少对被测对象的依赖

Dummy Objects
测试中必须传入的对象,传入这些对象并不会生产如何作用
Test Stub
测试桩接受SUT内部的间接输入,可以按照我们的要求返回特定的内容给SUT
Test Spy
将SUT内部的间接输出传到外部,不负责验证传出数据
Mock Object
和Test Spy类似,但负责验证传出的数据
Fake Object
和Test Stub类似,不关注SUT内部间接输入输出,仅仅是用来代替一个实际的对象

测试夹具(Test Fixture)

在测试之前自动初始化、回收资源。JUnit4中有@before和@After注解的方法,每个测试之前之后都执行一次。但这个缺点是效率低。

JUnit4引入类级别的夹具设置方法:

使用@beforeClass和@afterClass修饰,且方法用public static void 修饰

测试用例

JUnit4中测试方法用@Test修饰方法,一个测试用例可以有多个测试方法

测试套件(Test Suite)

将多个测试用例组装成一个测试套件,批量运行。使用@RunWith和@SuiteClasses注解空类

@RunWith(Suite.class) 表示此类为运行器
@SuiteClasses({}) 把测试用例类作为它的参数

断言(Assertiosn)

判断某个语句的结果是否为真,判断是否和预期相符,例如:Assert.assertEquals()方法。可以使用assert关键字,使用它必须指定Java的-ea参数,否则断言将被忽略

集成测试

验证功能模块之间集成后的正确性

JUnit4

优秀测试框架具备几点:

  • 单元测试必须独立于其他的单元测试
  • 单元测试中产生的错误必须被记录下来
  • 用户能够轻松指定要执行的单元测试

JUnit4采用Java 5的注解而不是子类,反射或命名机制来识别测试,它不是JUnit3.8的扩展版本,而是一个全新的测试框架

@Test

注解测试方法,参数:

  • expected 抛出异常类型,如果测试方法没有抛出这个异常,测试失败
  • timeout 设置超时时间,如果运行时间超过这个值,测试失败

参数化测试

  • 使用@RunWith 指定特殊运行器:Parameterized.class
  • 声明一个带参数构造参数
  • 创建一个@Parameterized.Parameters方法返回多组数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@RunWith(Parameterized.class)
public class ParamTest {
private Integer value;
public ParamTest(Integer value) {
this.value = value;
}
@Parameterized.Parameters
public static Collection<Integer[]> data() {
Integer[][] data = new Integer[][]{{1},{3},{5},{7}};
return Arrays.asList(data);
}
@Test
public void test() throws Exception {
assert this.value < 5;
}
}

测试运行器

执行测试方法的,默认测试运行器BlockJUnit4ClassRunner.可以自定义运行器,只要继承org.junit.runner.Runner,使用@Runwith显示地声明

Junit4断言

assertArrayEquals方法比较数组是否相等,只有两个数组的元素都相等,则两个数组相等。

assertThat断言

assertThat断言是结合Hamcrest新的断言语句。结合Hamcrest提供匹配符,Hamcrest是个测试辅助工具,提供一套通用匹配符Matcher,有个静态类Matchers

模拟利器Mockito

是一套通过简单方法对于指定接口或类生成Mock对象的类库

Stub对象

提供测试时所需要的测试数据,对各种交互设置相应的回应。when().thenReturn() 设置方法调用的返回值,也可以设置方法何时调用会抛出异常

when(mockUserService.getUserByName("devin")).thenReturn(new User("devin", "123"));

Mock对象

验证测试中所依赖对象间的交互是否能够达到预期,verify().methodXxx()语法来验证methodXxx方法是否按照预期进行了调用

1
2
3
4
5
6
when(mockUserService.getUserByName("devin")).thenReturn(new User("devin", "123"));
User devin = mockUserService.getUserByName("devin");
assertNotNull(devin);
verify(mockUserService).getUserByName("devin");

Mockito 使用

创建Mock对象

对于final类,匿名类和Java的基本类型无法进行Mock,创建方式:

  • mock(Class) 方法
  • @mock注解,注解需要MockitoAnnotations.initMocks方法初始化

设置Mock对象的期望行为及返回值

通过when(mock.someMethod).thenReturn(value),对于static和final修饰的方法无法设定

  • when().thenReturn()
  • doReturnn().when().methodXxx()
  • doNothing().when().methodXxx() 返回void

验证交互行为

Mock对象一旦建立会自测试动记录自己的交互行为

  • verify(mock, atLeastOnce()).methodXxx 方法至少调用一次
  • verify(mock, atLeast(1)).methodXxx
  • verify(mock, atMost(1)).methodXxx 至多调用一次
    • verify(mock, never()).methodXxx 从未

测试整合之王Unitils

构建DbUnit和EasyMock项目之上,与JUnit和TestNG结合,支持数据库测试、支持Mock对象进行测试,并提供与Spring和Hibernate集成

配置文件

  • unitils-defaults.properties 默认配置文件,开启所以功能
  • unitils.properties 项目级配置文件
  • unitils-local.properties 用户级配置文件

断言

assertReflectionEquals 反射断言

判断两个对象是否相等,判断对象属性值是否一样,不需要重写equals方法

ReflectionAssert.AssertReflectionEquals()
  • IGNORE_DEFAULTS 忽略Java类型默认值
  • LENIENT_DATES 忽略Date的值是否相等,比较是不是被设置值或都为null
  • LENIENT_ORDER 忽略集合数组中元素顺序

assertLenientEquals

忽略顺序忽略默认值的断言

assertPropertyXxxEquals 属性断言

只比较对象特定属性assertPropertyReflectionEquals和assertPropertyLenientEquals

Spring Boot

@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
@ActiveProfiles(“dev”)

Web Flux Test

WebTestClient 测试WebFlux服务器端点,无论是否有正在运行的服务器。
测试没有正在运行的服务器与Spring MVC中的MockMvc相当,其中使用模拟请求和响应而不是使用套接字通过网络连接

Maven Test

mvn test -Dtest=[ClassName]
执行测试类
mvn test -Dtest=[ClassName]#[MethodName]
执行测试方法

Linux-运维

修改SSH端口和禁止Root远程登录

修改端口

/etc/ssh/sshd_config文件中
修改SSH端口,修改port后的端口

禁止Root远程登录:

把PermitRootLogin yes 改为 PermitRootLogin no
重启服务,service ssh restart

流量监控

vnstat

安装

apt-get install vnstat

创建监听数据库

vnstat -u -i eth0    ->    eth0是系统网卡

启动服务

service vnstat start

开机自启动,在/etc/rc.local文件中加:

service vnstat start

查看流量情况命令

每天的,vnstat -d
每月的,vnstat -m    
实时流量,vnstat -l -i eth0
查看五秒平均流量,vnstat -tr -i eth0

不能统计流量,需要修改.eh0权限,在/var/lib/vnstat目录中

chown vnstat:vnstat .eth0 -R
chmod 0640 .eth0

rz,sz命令

sz:将选定的文件发送(send)到本地机器
rz:运行该命令会弹出一个文件选择窗口,从本地选择文件上传到服务器(receive)

注意:单独用rz会有两个问题:上传中断、上传文件变化(md5不同),解决办法是上传是用rz -be,并且去掉弹出的对话框中“Upload files as ASCII”前的勾选。

-b binary 用binary的方式上传下载,不解释字符为ascii
-e 强制escape 所有控制字符,比如Ctrl+x,DEL等

安装

下载地址    http://www.ohse.de/uwe/software/lrzsz.html
配置        ./configure --prefix=/usr/local/lrzsz
编译        make
安装        make install

创建连接

cd /usr/bin  
sudo ln -s /usr/local/lrzsz/bin/lrz rz  
sudo ln -s /usr/local/lrzsz/bin/lsz sz 

/boot分区不足,清理boot分区

查看系统已安装内核

dpkg --get-selections|grep linux-image

查看系统使用内核

uname -a    

删除不使用内核

sudo apt-get purge 内核名称
sudo apt-get remove linux-image-(版本号)

清理

清理/usr/src下的内核目录
sudo apt-get autoremove 删除残留文件

xshell连接linux系统,操作卡

关闭DNS解析,修改/etc/ssh/sshd_config文件中:

UseDNS no
/etc/init.d/sshd restart

系统使用技巧

  • 执行某命令时忘记加sudo, 可以输入sudo !! 即可,这里的 !! 代表上一条命令

Git

git init        初始化 git 仓库
git fsck        仓库一致性检查
git gc            压缩
git describe     显示提交易记名称(最近的里程碑名字 tag_name-<n>-ID)
git mv <file> <file>    改名操作

git rebase

对提交执行变基操作,实现将指定范围的提交嫁接到另外一个提交之上

git archive

归档打包

git archive -o <name>.zip HEAD
git archive -o <name>.zip HEAD <path>...
git archive --format=tar --prefix=1.0/ v1.0 | gzip > foo-1.0.tar.gz

使用tar格式和提交ID或里程碑ID,ID会记录在文件的文件头中,可以用下面命令获取提交ID

git tar-commit-id

忽略文件或目录 export-ignore

.gitignore

作用范围是其在的目录及其子目录

git status --ignored        可以看到忽略的文件
git add -f                强制添加忽悠的文件

独享式忽悠

  • 在.git/info/exclude来设置文件忽略(针对具体版本库)
  • 配置变量core.excludesfile设置文件忽略(所有本地版本库)

忽略语法

* 代表任意多字符
? 一个字符
/path 忽略此目录下文件,非子目录
path/ 忽略整个目录,包括子目录
!<file/path> 不忽略

git add

git add -u        把工作区文件加到暂存区(被版本库追踪的)
git add -A        把工作区文件加到暂存区(包括未被版本库追踪的)
git add -i        选择性添加到暂存区

git status

根据文件时间戳,长度判断文件是否改变,如果时间戳改变,再看内容是否改变。文件内容保存再.git/objects目录下

参数 描述
-s 查看精简状态,第一列M表示:版本库和暂存区的文件比较,第二列M表示:工作区和暂存区
-b 显示当前分支名

git commit

git commit -e -F .git/COMMIT_EDITIMSG        重新提交(.git/COMMIT_EDITIMSG 是上次提交日志    )
git commit -a -m                 偷懒提交,不用git add
git commit --amend -m                修改最新提交说明
git commit -C 提交ID            重用提交的提交说明

git log

默认是指HEAD

参数 描述
–stat 查看提交文件变更记录
–oneline,–pretty=oneline 查看精简日志,前面显示提交哈希值前几位,后面显示全部
–graph 查看提交关系图(树结构显示)
–pretty=raw 显示commit的原始数据(parent属性)
–pretty=fuller 显示作者和提交者
–decorate 显示提交关联引用
- 最近几条日志
-p 显示文件具体改动

git config –global alias.lg “log –graph –pretty=format:’%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset’ –abbrev-commit –date=relative”

git diff

默认是把工作区和暂存区的文件做比较

git diff HEAD    把工作区和版本库的文件做比较
git diff --cached/--staged        把暂存区和版本库的文件做比较
git diff 提交ID1 提交ID2
git diff 提交ID1 提交ID2 --<paths>

–word-diff 对每个词比较

git checkout

默认是暂存区,覆盖工作区文件

git checkout ./--file        撤销工作区全部文件或某个文件未提交的修改
git checkout HEAD ./<file>    用版本库的全部或部分文件替换暂存区和工作区中的文件

创建和切换到新的分支

git checkout <new_branch> <branch>
git checkout -b test       基于当前分支新建分支test,并切换到test分支下

切换到某个提交,是分离头指针,head指向具体提交

git checkout 提交ID

汇总工作区、暂存区、与HEAD的差异

git checkout

git reset

没有指定提交,默认是HEAD

git reset HEAD <paths>        把版本库的全部文件替换暂存区的

git reset

--hard HEAD^        替换暂存区和工作区的全部文件(重置引用指向)
--soft HEAD^        不改变暂存区和工作区内容(仅重置引用指向)
--mixed HEAD^        重置暂存区,不改变工作区(重置引用执行,默认是这个参数)

git rm

git rm --cached <file> 从暂存区删除文件,不影响工作区

git ls-tree、ls-files

git ls-tree -l         HEAD 查看版本库的目录树(-l显示文件大小)
git ls-files -s     查看暂存区的目录树(第三个字段表示暂存区编号)
git ls-files --with-tree=HEAD^    查看历史版本的文件列表

git write-tree可以把暂存区的目录树写入git对象库,然后用git ls-tree查看。如果是tree对象,可以加上-r -t参数显示tree树内容

git clean

git clean -fd        清除未加入版本库的文件和目录
git clean -nd        强制删除目录和文件

git stash

保存工作区和暂存区的修改,然后改动全不见了。

git stash    保存进度
save 指定说明
--patch 显示工作区和HEAD的差异
-k 不会重置暂存区

查看所以进度

git stash list
git reflog show refs/stash

从最近保存的进度进行恢复

git stash pop    会删除进度
[--index] 恢复工作区,且尝试恢复暂存区
git stash apply 不会删除进度

其他命令

git stash clear 清除所有进度
git stash branch <branch name> <stash> 基于这个进度创建分支

git对象

对象保存在.git/objects目录下,对象的40位sha1哈希值前2位作为目录,后38作为文件名

git cat-file

git cat-file -t 查看对象类型
git cat-file -p    查看对象内容
git cat-file -p HEAD^:file > file    从某个提交中恢复文件
git show HEAD^:file > file

符号

^            指父提交
^+数字        表示第几个父提交
~+数字        指祖父提交
^{对象}        表示提交对应的对象
提交ID:file    对应提交的文件
:file        暂存区的文件

git reflog

.git/logs记录分支的变更,查看git config core.logallrefupdates是否开启。

git reflog show master    查看变更记录(<ref>@{<n>}引用之前第几次改变)

git rev-parse

git rev-parse HEAD        查看引用对应sha1哈希值
git rev-parse HEAD:file
参数 描述
–symbolic –branches 显示分支
–symbolic –tags 显示里程碑
–git-dir 显示版本库位置
–show-cdup 工作区目录的深度
–symbolic –glob=refs/* 显示所有引用
:/“commit a” 在提交日志中查找提交

git rev-list

参数 描述
–oneline A 显示A版本库以来所有的历史提交
–oneline D F 提交历史并集
–oneline ^D F(D..F) 排除D的历史提交
–oneline D…F 排除共同的历史提交
–oneline D^@ D的历史提交,自身除外
–oneline D^! 提交本身,不包括历史

git blame

显示文件内容,包括每行提交版本,提交者

-L n, m 从第n行开始,显示m行

授权

ssh-keygen -t rsa 生成公钥密钥

git config

参数

--global 全局设置

属性

user.email                邮箱
user.name                名字
alias.<name> '命令'        设置别名
core.editor "vim"        默认情况下 git 用的编辑器是 vi,设置Editor使用vim
color.ui true            开启给 Git 着色
core.quotepath false    显示中文文件名
http.postBuffer 524288000 增加Git’s HTTP buffer                                                                                                            

默认这些配置都在 ~/.gitconfig,可以输入 git config -l 命令查看

分支

git branch                                
    查看下本地分支情况
git branch -a                        
    查看所有分支,包括本地和远程
git branch -r                        
    查看远程分支
git branch test                        
    新建分支test
git branch -d test                    
    删除分支test
git branch -D test                    
    强制删除分支test,如果test分支没有整合
git branch --set-upstream-to=origin/<branch> master
    set tracking information for this branch

版本

git tag                            查看版本
git tag v1.0                        贴标签,版本控制

合并

git merge    test                        合并分支, 在master分支执行这命令

同步

git push origin master                本地代码推到远程 master 分支
git push -f                                           强推,覆盖相同的内容
git pull origin master                远程最新的代码更新到本地
git clone url                        把项目 clone 到了本地

关联

git remote add origin url                与 GitHub 上的项目进行关联,origin 是给这个项目的远程仓库起的名字
git remote remove <name>                 取消关联
git remote rm origin                    删除关联
git remote -v                        当前项目有哪些远程仓库    

快捷键

Sublime text 3

快捷键 描述
Ctrl Shift L 选中多行编辑
Ctrl J 多行变一行

IntelliJ IDEA

快捷键 描述
Ctrl+Shift+V 选择剪切板上的文本进行插入
右击断点 可以看到断点属性
Ctrl+H 打开类的层次结构
Ctrl+W 选择文本
Alt+F8/Alt+点击表达式 调试时看表达式值
Ctrl+Q 查看文档说明
Ctrl+P 查看方法参数提示
Ctrl+B 打开方法或类声明地方
Ctrl+N 搜索类
Ctrl+Shift+N 搜索文件
Ctrl+Shift+Alt+N 搜索文本
Ctrl+Alt+V 把表达式提出为局部
Alt+Shift+C 查看项目最近修改地方
Ctrl+` 修改style/color scheme or keymap
Ctrl+Shift+Enter 自动补全代码if,do-while,return,try-catch
Ctrl+Alt+Shift+C 复制field/method/class/file
Ctrl+Shift+向下上箭头 移动代码块
Alt+Shift+F10 打开run/debug菜单
Ctrl+Shift+I 预览class/file/symbol代码
Shift+F6 重命名
Alt+Home 导航栏,修改项目view
Alt+F7 搜索方法,变量在哪被引用
Ctrl+Shift+F 全局搜索
Ctrl+Shift+Z 反撤销,Ctrl+Z的反操作

Visual Studio

快捷键 描述
Ctrl+J 代码提示
Ctrl+Shitf+Space 参数提示
Ctrl+K+F 格式化整个块
Ctrl+K, F 格式化整个文件
Ctrl +] 检查括号匹配(在左右括号间切换)
Ctrl+Shift+7(8) 方法定义和调用之点切换
Ctrl+K,C 注释代码
Ctrl+K,U 取消注释
Ctrl+Shift+L 删除当前行

Maven

语法

mvn [options] [<goal(s)>] [<phase(s)>]
options     可以用mvn -h 或 mvn --help查看
phase        是生命周期阶段

生命周期阶段

有clean、default和site几类,下面出现的顺序就是执行顺序。

clean

pre-clean, clean, post-clean

default

validate, initialize, generate-sources, process-sources, generate-resources, process-resources, compile, process-classes, generate-test-sources, process-test-sources, generate-test-resources, process-test-resources, test-compile, process-test-classes, test, prepare-package, package, pre-integration-test, integration-test, post-integration-test, verify, install, deploy

site

pre-site, site, post-site, site-deploy

命令

mvn package -Dmaven.skip.test=true 
    打war包
java -cp XXX.jar Main
    执行main方法

目标

Dependency 插件

分析

mvn dependency:analyze

查看项目依赖

mvn dependency:resolve
mvn dependency:tree            列出直接和传递性依赖,以树形式打印
mvn install -X                打开调试标记,查看完整依赖踪迹,包括因为冲突被拒绝加入的构件

Exec 插件

运行Java类或其他脚本

mvn exec:java -Dexec.mainClass=com.epdc.maven.App

Surefire插件

处理单元测试的,如下配置

1
2
3
4
5
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration></configuration>
</plugin>

运行到test阶段为止所有生命周期阶段

mvn test    有测试单元失败,会停止当前的构建

configuration

忽略测试失败,或者mvn test -Dmaven.test.failure.ignore=ture

<testFailureIgnore>true</testFailureIgnore>

完成跳过单元测试,或者mvn test -Dmaven.test.skip=ture

<skip>true</skip>

Assembly插件

创建应用程序特有分发包,包括项目的二进制文件和所有的依赖,配置

1
2
3
4
5
6
7
8
9
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>

Archetype 插件

generate

创建项目

mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=my-app    java项目
mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=my-app -DarchetypeArtifactId=maven-archetype-webapp    web项目

Jetty插件

运行web应用,配置

1
2
3
4
5
6
7
8
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.3.14.v20161028</version>
<configuration>
<scanIntervalSeconds>1</scanIntervalSeconds>
</configuration>
</plugin>

启动web应用

mvn jetty:run

Help插件

pom继承超级pom 和 父pom, 得到混合各个pom配置的有效pom。effective-pom目标可以查看有效pom

mvn help:effective-pom

Zookeeper

配置(conf/zoo.cfg)

启动时会找zoo.cfg文件作为默认配置文件,所以复制一份zoo_sample.cfg

tickTime:服务器之间或客户端与服务器之间维持心跳的时间间隔,每个 tickTime 时间就会发送一个心跳
dataDir :保存数据的目录,将写数据的日志文件也保存在这个目录里
clientPort:监听这个端口,接受客户端的访问请求

启动命令

./zkServer.sh start

客户端

启动

./zkCli.sh -server localhost:2181

占用8080端口

zookeeper有个内嵌的管理控制台是通过jetty启动,也会占用8080端口。可以启动脚本中修改

admin.serverPort=port 

或者停止这服务

admin.enableServer=false

问题

ruok is not executed because it is not in the whitelist.

配置那些命令可用 4lw.commands.whitelist=stat, ruok, conf, isro 配所有命令可用 4lw.commands.whitelist=*

tomcat

启动多个

修改http端口(默认8080)

1
2
<Connector port="8080" protocol="HTTP/1.1" connectionTimeout="60000"
redirectPort="8443" disableUploadTimeout="false" executor="tomcatThreadPool" URIEncoding="UTF-8"/>

修改远程停服务端口(默认8005)

1
<Server port="8005" shutdown="SHUTDOWN">

修改AJP端口(默认8009)

1
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

nginx

启动、停止和重新加载服务

nginx
nginx -s stop
nginx -s reload
nginx -s quit        退出
nginx -t             检查配置文件

配置(/etc/nginx/nginx.conf、/etc/nginx/conf.d/default.conf)

worker_processes
    进程的个数,建议设置为CPU的个数
worker_connections
    单进程的最大连接数
server
    listen                监听端口
    server_name            服务的域名,可以配置多个用空格隔开

负载均衡

在http中配置

#设定负载均衡的服务器列表  
upstream mysvr {  
    #weigth参数表示权值,权值越高被分配到的几率越大    
    #同一机器在多网情况下,路由切换,ip可能不同
    server 127.0.0.1:8080 weight=1;  
    server 127.0.0.1:8090 weight=1;  
    server 127.0.0.1:8070 weight=1;  
}

代理、反向代理

nginx 403 Forbidden

nginx的启动用户默认是nginx用户,需要修改web目录的权限

静态文件缓存

server中配置缓存,需要指定root值,否则默认是Nginx的目录,会导致找不到文件。

1
2
3
4
5
6
7
8
9
10
11
#静态文件缓存时间设置
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ {
root /root/blog_front/blog-front/dist;
expires 30d;
}
#静态文件缓存时间设置
location ~ .*\.(js|css)?$ {
root /root/blog_front/blog-front/dist;
expires 1h;
}