问题一
报错如下:
搜寻后发现此类谬误和数据库的字符集有关系之所以之前没发现此类问题是因为之前测试时只测试了保留英文字符,然而当咱们存储中文字符时就会呈现此类谬误。
很显然咱们建库时并没有留神到这些,并且在以后环境下默认建库并不反对中文。
所以要解决此类谬误只须要批改一下字符集即可。
或者将咱们的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");
这样咱们在执行单元测试时就能够很分明的晓得哪里出了问题。