单元测试

1. Mockito 单元测试开发中,我们经常会遇到测试的类有很多依赖的类、对象、资源,从而形成巨大的依赖树,mock可以模拟外部依赖,适应单元测试。 比如我们在开发中很容易出现这种情况: (a)依赖(b)依赖(c)依赖(d) 这种情况下单元测试就变得极其复杂,而且如果需要测试数据库或网络请求返回值的情况,就更加复杂了。我们总不至于去修改真实数据库,去修改真实的网络情况吧。 但是如果我们引入Mockito情况就会变得简单许多,我们可以mock虚拟的依赖,并可以轻松的修改返回值甚至抛出异常: (a)依赖(mock b) 1.1 Mockito 的简单用法 Mockito是一个功能非常丰富的框架,下面介绍几个典型和常用的方法,详细的使用可以到官网上查询。 Mockito官网{:target="_blank"} Mocktio文档{:target="_blank"} 我们在非Spring Boot项目中使用Mockito需要手动引入依赖,Spring Boot项目中Mocktio的使用会在下面介绍。 <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <scope>test</scope> </dependency> 1.1.1 mock对象 // 模拟LinkedList 的一个对象 LinkedList mockedList = mock(LinkedList.class); // 此时调用get方法,会返回null,因为还没有对方法调用的返回值做模拟 System.out.println(mockedList.get(0)); 1.1.2 方法调用的返回值 // 模拟获取第一个元素时,返回字符串first。 给特定的方法调用返回固定值在官方说法中称为stub。 when(mockedList.get(0)).thenReturn("first"); // 此时打印输出first System.out.println(mockedList.get(0)); 1.1.3 方法调用抛出异常 // 模拟获取第二个元素时,抛出RuntimeException when(mockedList.get(1)).thenThrow(new RuntimeException()); // 此时将会抛出RuntimeException System.out.println(mockedList.get(1)); 如果一个方法没有返回值类型,那么可以使用此方法模拟异常抛出 doThrow(new RuntimeException("clear exception")).when(mockedList).clear(); mockedList.clear(); 1.1.4 调用方法时的参数匹配 // anyInt()匹配任何int参数,这意味着参数为任意值,其返回值均是element when(mockedList.get(anyInt())).thenReturn("element"); // 此时打印是element System.out.println(mockedList.get(999)); 1.1.5 验证方法调用次数 // 调用add一次 mockedList....

June 13, 2018 · 4 min · sunbufu

发布jar包到maven中央仓库

一、写在前面 最近做了一个权限认证的框架,想把jar发布到maven中央仓库上,方便大家使用。于是就有了这篇博客。 二、具体步骤 2.1 注册账号 首先要做的就是注册账号,这个账号可用于提出申请groupId的Issue,也可用于发布和登录到中央仓库。 2.1.1 注册sonatype 工单地址:https://issues.sonatype.org 2.2 申请groupId 创建申请groupId的工单 工作人员会审核你的申请,如果你的groupId是你的域名,还需要提供一些证明。如果没有域名也可以使用一些开源网站,例如com.github.xxx,io.github.xxx等。 如果审核时间很长的话,可以尝试再次提交一个工单。工作人员在审核的时候可能根据最近的Issue来的。 2.3 配置GPG 这次我用的mac,所以我使用brew安装的gpg。 brew install gpg 然后建立软连接到/usr/local/bin/ sudo ln -s /usr/local/Cellar/gnupg/2.2.7/bin/gpg /usr/local/bin/gpg 因为我使用的版本是2.2.7,加密多次失败后。网上查到需要进行一些额外配置。 在gpg的安装目录(~/.gnup)下新建两个配置文件: gpg.conf: use-agent pinentry-mode loopback gpg-agent.conf: allow-loopback-pinentry 2.4 生成秘钥 执行命令,并填入一些信息后生成秘钥 gpg --gen-key gpg --list-keys pub rsa2048 2018-05-18 [SC] [有效至:2020-05-17] xxxxx uid [ 绝对 ] sunbufu <sunyoubufu@qq.com> sub rsa2048 2018-05-18 [E] [有效至:2020-05-17] 发布公钥到服务器 gpg --keyserver hkp://keyserver.ubuntu.com:11371 --send-keys xxxxx 2.5 配置settings.xml 首先需要配置用户名和密码(2.1.1中注册的用户名和密码) <server> <id>ossrh</id> <username>用户名</username> <password>密码</password> </server> 2....

June 13, 2018 · 1 min · sunbufu

数据库范式

数据库范式的定义 在设计数据库的时候,为了设计出合理的关系型数据库,就需要遵循一些规范要求,这些规范要求被成为数据库范式。 目前,关系型数据库主要有六种范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴斯-科德范式(BCNF)、第四范式(4NF)和第五范式(5NF,又称完美范式)。一般来说,数据库满足前三个范式就可以了。 第一范式(1NF) 定义 所谓第一范式(1NF)是指在关系模型中,对域添加的一个规范要求,所有的域都应该是原子性的,即数据库表的每一列都是不可分割的原子数据项,而不能是集合,数组,记录等非原子数据项。即实体中的某个属性有多个值时,必须拆分为不同的属性。在符合第一范式(1NF)表中的每个域值只能是实体的一个属性或一个属性的一部分。简而言之,第一范式就是无重复的域。 解释 第一范式是指数据库表中的每个字段都是不可分解的,即数据库表中的字段具有原子性。 例如,我们有个学生信息表,如下: id name age address 001 张三 26 山东省青岛市XX县XX镇XX村XX号 002 李四 25 河南省开封市XX县XX区XX号 这个表就违反了第一范式,因为表中的字段 地址(address) 可以重新拆分为 省(address_province) 市(address_city) 详细地址(address_detail)。 id name age address_province address_city address_detail 001 张三 26 山东省 青岛市 XX县XX镇XX村XX号 002 李四 25 河南省 开封市 XX县XX区XX号 如上图所示的表遵循了第一范式,对学生的地址管理就方便了很多,也能提高数据库的性能。比如我们要查询青岛市的学生有谁的时候。...

June 13, 2018 · 1 min · sunbufu

http

一、TCP/IP 协议介绍 在介绍 HTTP 协议之前,先简单说一下TCP/IP协议的相关内容。TCP/IP协议是分层的,从底层至应用层分别为:物理层、链路层、网络层、传输层和应用层,如下图所示: 从应用层至物理层,数据是一层层封装,封装的方式一般都是在原有数据的前面加一个数据控制头,数据封装格式如下: 其中,对于TCP传输协议,客户端在于服务器建立连接前需要经过TCP三层握手,过程如下: 二、HTTP协议 2.1 简介 超文本传输协议(Hypertext Transfer Protocol,简称HTTP)是应用层协议,自 1990 年起,HTTP 就已经被应用于 WWW 全球信息服务系统。 HTTP 是一种请求/响应式的协议。一个客户机与服务器建立连接后,发送一个请求给服务器;服务器接到请求后,给予相应的响应信息。 HTTP 的第一版本 HTTP/0.9是一种简单的用于网络间原始数据传输的协议; HTTP/1.0由 RFC 1945 定义 ,在原 HTTP/0.9 的基础上,有了进一步的改进,允许消息以类 MIME 信息格式存 在,包括请求/响应范式中的已传输数据和修饰符等方面的信息; HTTP/1.1(RFC2616) 的要求更加严格以确保服务的可靠性,增强了在HTTP/1.0 没有充分考虑到分层代理服务器、高速缓冲存储器、持久连接需求或虚拟主机等方面的效能; 安全增强版的 HTTP (即S-HTTP或HTTPS),则是HTTP协议与安全套接口层(SSL)的结合,使HTTP的协议数据在传输过程中更加安全。 2.2 协议结构 HTTP协议格式也比较简单,格式如下: 2.3 HTTP 协议举例 下面是一个HTTP请求及响应的例子: 2.4 请求头格式 a) 通用头(general-header): Cache-Control:客户端希望服务端如何缓存自己的请求数据,如"Cache-Control: no-cache","Cache-Control: max-age=0"; Connection:客户端是否希望与服务端之间保持长连接,如"Connection: close", “Connection: keep-alive"; Date:只有当请求方法为POST或PUT方法时客户端才可能会有些字段; Pragma:包含了客户端一些特殊请求信息,如 “Pragma: no-cache” 客户端希望代理或应用服务器不应缓存与该请求相关的结果数据; Via:一般用在代理网关向应用服务器发送的请求头中,表明该来自客户端的请求经过了网关代理, 格式为:"Via: 请求协议版本 网关标识 [其它信息] ", 如 :” Via: 1....

June 2, 2018 · 3 min · sunbufu

java下的cookie和session

Session是一种服务器端技术, Session 对象在服务器端创建,通常采用散列表来存储信息,例如, Tomcat 的 Session 实现采用 HashMap 对象来存储属性名和属性值。 Cookie是由 Netscape 公司发明的、用于跟踪用户会话的一种方式。 Cookie 是由服务器发送给客户的片段信息,存储在客户端浏览器的内存中或硬盘上,在客户随后对该服务器的请求中发回它。 Cookie小结 Cookie在服务端创建 Cookie cookie = new Cookie(name,value); Cookie保存在浏览器端 response.addCookie(cookie); Cookie的生命周期和上传路径均可指定。 Cookie cookie = new Cookie("mykey", "myvalue");//新建cookie cookie.setMaxAge(60 * 60 * 24);//设置cookie的生命周期是一天 cookie.setPath(req.getContextPath() + "/cookie.action");//只有在访问/cookie.action时才会上传 resp.addCookie(cookie);//添加cookie Cookie可以被多个浏览器共享 一个web应用可以保存多个cookie(放置在同一个文件内部) ,最多不要超过20个,每个Cookie的大小限制为4kB,因此Cookie不会塞满你的硬盘更不会被作为"拒绝服务"的攻击手段。浏览器一般保存的Cookie不会超过300个 Cookie存放中文,出现的乱码问题 //存放 String val = java.net.URLEncoder.encode("中文名称","utf-8"); Cookie cookie = new Cookie("name","val"); //读出 String val = java.net.URLDecoder.decode(cookie.getValue("name"),"utf-8"); out.println("name="+val) session小结: Session是存放在服务器的内存中 HttpSession session = req....

June 2, 2018 · 1 min · sunbufu