共计 3681 个字符,预计需要花费 10 分钟才能阅读完成。
问题一
报错如下:
搜寻后发现此类谬误和数据库的字符集有关系之所以之前没发现此类问题是因为之前测试时只测试了保留英文字符,然而当咱们存储中文字符时就会呈现此类谬误。
很显然咱们建库时并没有留神到这些,并且在以后环境下默认建库并不反对中文。
所以要解决此类谬误只须要批改一下字符集即可。
或者将咱们的 url 改为如下重建一次数据库
jdbc:mysql://localhost:3310/process-evaluation?useUnicode=true&characterEncoding=utf-8
尽管说在本地解决很简略,然而如果只是这样做的话在近程机器人运行时还会产生报错, 因为仅仅扭转链接时的 url 链接并不能间接扭转现有数据库的配置。
那么我么就须要像在本地那样重新配置字符集或是从新建设数据库,那么咱们就须要理解远端机器人的数据库是怎么建设的。
咱们在提 PR 时在什么环境下跑 pipeline,按什么程序,要进行什么操作,这些配置都和.gitlab-ci.yml 文件相干
之前已有篇文章讲过其大抵配置办法,在此就不过多赘述。
spring-test:
tags:
- docker
stage: unit-test
image: maven:3.6-openjdk-8
services:
- name: mysql:5.7
alias: mysql
variables:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: process-evaluation
. . .
before_script:
- cd api
script:
- env
- mvn -v
- mvn package
rules:
- if: $CI_PIPELINE_SOURCE == 'merge_request_event'
其中 tags 定义了哪些 runner 实用该 job,咱们以后应用的是 docker 环境,其中的 image 和咱们之前配置 docker 时遇到的雷同,也指的是映像,所以就须要 docker 环境。
这些是官网对其的阐明——当你配置 CI/CD 时,能够用 image 创立一个容器当 job 运行时,然而 image 只能有一个,如果还须要其余 image 就须要用 service 来指定。service 能够创立另一个容器,并且这两个容器间可互相通信。
有了这些咱们运行后盾所须要的环境就只差 mysql 了,又因为 mysql 须要配置所以就采纳 service 进行引进。
官网也给出了相应的配置办法
services:
- mysql:latest
variables:
# Configure mysql environment variables (https://hub.docker.com/_/mysql/)
MYSQL_DATABASE: $MYSQL_DATABASE
MYSQL_ROOT_PASSWORD: $MYSQL_ROOT_PASSWORD
其中的 service 项能够应用 Docker Hub 中任何 docker 映像,例如,要应用 MySQL 5.5,请应用 mysql:5.5。
并且 imgge 可承受除此以外的其余环境变量,具体变量和 docker hub 中对 mysql 的阐明雷同。
然而下面这些并不能解决咱们遇到的问题——怎么扭转数据库的字符集?
docker 环境变量并不反对配置字符集,起初又发现官网文档中也写出了怎么运行 mysql 通过 shell。
然而到第一步就呈现了问题,以后环境并不反对执行 apt install,image 也不能进行变动,通过 tags 的运行环境也不能随便更改,毕竟咱们也须要 docker 环境。
所以又尝试独自运行一个 database-init 的 job,在下面进行这些操作,然而每个 job 之间又都是独立的,也就是说咱们在 database-init 中初始化完了数据库,等此 job 完结后这个容器就被开释了,咱们之后再用的又是一个全新的容器。所以咱们只能在 service 中作改变,然而依照官网文档中所说,service 中只能配置环境变量。
除此之外还有另一种办法就是本人写一个 dockerfile,初始化一个字符集为 utf8 的 docker5.7 的映像再通过阿里云构建,最初再在 service 中引入。
这样的话尽管能够解决但也会遇到其余问题,并且起初咱们能够得悉在 service 中作改变就能够解决此问题。再此就不做开展。
上面是老师给出的解决办法:
能够间接通过 command 来进行操作。尽管问题解决了,然而新的问题也来了——为什么我找不到能够这么解决,官网文档上也没找到这样的操作。
起初又认真查看了官网文档,发现的确有对 command 的解释:
利用作容器命令的命令或脚本。它被翻译成在镜像名称之后传递给 Docker 的参数。
总接下来还是看官网文档不认真,这是官网文档的菜单。
之前把注意力全副集中在 mysql service 中,当看到其中能够通过装置 mysql-client
来执行命令时就想当然认为想要执行相应命令就只有这一个办法。
总结:官网文档还是要认真看,不能自己想什么就是什么,可能官网文档的编排和咱们平时浏览习惯不同,然而当遇到问题时还是要置信官网文档。
问题二 单元测试时呈现问题
呈现问题的行:
org.assertj.core.api.Assertions.assertThat(resultUser).isEqualTo(mockResultUser1);
先来看一下 mockResultUser1 是怎么来的
UserService userServiceSpy = Mockito.spy(this.userService);
UserServiceImpl userServiceImplSpy = (UserServiceImpl) userServiceSpy;
User mockResultUser1 = new User();
Mockito.doReturn(mockResultUser1).when(userServiceImplSpy).updateNameAndEmailField(Mockito.any(User.class), Mockito.anyString(), Mockito.anyString());
咱们设定当调用 updateNameAndEmailField
时返回 mockResultUser1。
resultUser 为 null,那咱们再来看看 resultUser 从哪来的。
User user = new User();
User resultUser = userServiceImplSpy.updateNameAndEmail(id, user);
@Override
public User updateNameAndEmail(Long id, User user) {User oldUser = this.userRepository.findById(id).get();
return this.updateNameAndEmailField(oldUser, user.getName(), user.getEmail());
}
public User updateNameAndEmailField(User oldUser, String name, String email) {oldUser.setName(name);
oldUser.setEmail(email);
return this.userRepository.save(oldUser);
}
明确了大体流程接下来就是打点,察看为什么断言不成立,那一部和咱们预期不同。
咱们能够看到在最外层传参都是没问题的,并且 resultUser 也的确为 null。
那么就要进一步区 service 层中打点。
updateNameAndEmaile 中也没有问题。
到这里咱们就能发现问题了,email 为 null,这也就阐明了咱们没有对 email 设初值,然而执行过程中没有产生报错,阐明这也是能够的,比方咱们当前情况下也能够将 email 设置为 null,因为咱们的报错只是因为断言不正确。
那么为什么会返回 null 呢,次要还是因为上面:
Mockito.doReturn(mockResultUser1).when(userServiceImplSpy).updateNameAndEmailField(Mockito.any(User.class), Mockito.anyString(),Mockito.anyString());
咱们设置当传给 updateNameAndEmailField
(user,String,String)时才会返回 mockResultUser1,然而 null 并不在Mockito.anyString()
的范畴里,所以才会返回 null,如果咱们改为 Mockito.any()
就不会呈现下面的断言谬误。
当然咱们还是应该依照原先的思维,给 email 设定初始值,并且最好在 updateNameAndEmailField
中退出断言。、
Assert.notNull(email, "email 不能为 null");
这样咱们在执行单元测试时就能够很分明的晓得哪里出了问题。