Jenkins_CICD_实现构建即自动测试


目录:

需求 & 背景

将自动化测试集成到Jenkins中,最终实现每次构建部署时自动完成基础测试

因为在日常的部署中,有出现Pod和容器正常启动,但运行报错,导致服务不可用的情况。而CI/CD的频率较高,单个项目一天可能更新三到四次,从成本角度来说无法实现每次更新后都有测试工程师进行覆盖。这种情况从运维角度来解决无非是监控指定端口能否访问,但这样实际是脱离业务的,毕竟如果用户访问不了,一切白搭。

翻看了百度和Google的资料,并没有发现能解决该痛点的解决方案。最常见的方案通常是测试工程师从他们的windows本机部署Jenkins使用脚本来完成测试(环境在本机已经配置好)。参考过同事,他那边是使用gitlab-runner来提供python的运行环境,所以也曾发散想过是否能通过Jenkins-Node节点的方式来实现。后来发现即使是使用Node,那也得Node有python环境也需要我手动来装,那不如就直接装进主节点。

所以打算将运维和测试进行结合,部署后只保证服务基本能访问,剩下的功能、接口测试由专业的测试工程师解决。

介绍

本质其实也是Jenkins执行shell命令,只不过Jenkins是部署在服务器中。所以在Jenkins容器中安装需要的python环境。如果是以K8S形式部署,接下来我会将实现步骤打包成Docker镜像。列出本次自动化测试中用到的软件及三方库介绍:

Jenkins

开源的CI/CD自动化平台。

pytest

Python的一款开源单元测试框架。

selenium

开源的web自动化工具,模拟用户在浏览器中进行操作。

Chromedriver 是 Chrome 驱动,是 Python 爬虫使用的 selenium 模块用来模拟打开谷歌浏览器所必须的一个文件,能模拟在谷歌浏览器上的操作。

allure

开源的测试报告框架,用于生成测试报告,与pytest配合效果奇佳。

使用

使用流程如下:

  1. 编写自动化测试用例(本人只写了一个,就是通过selenium来测试平台能否正常访问);
  2. 将含测试用例的目录推送到Jenkins容器中(不管以gitlab还是以链接的形式);
  3. 安装运行环境,运行测试用例进行测试;
  4. 通过Jenkins-UI编写执行脚本;
  5. Jenkins下载allure插件并配置,使其自动生成测试报告;

测试用例编写

pytest/  # 项目目录结构
├── config
│   └── yaml_load.py  # 封装配置文件函数
├── data
│   └── login.yaml  # 登录账号密码
└── test_login.py  # 测试用例,实现功能:链接指定网站,输入账号密码并登录
$ cat pytest/data/login.yaml  # 登录账号密码
-
  user: root
  pwd: xxxxxxxx

$ cat pytest/config/yaml_load.py  # 封装配置文件函数
import yaml


def load_yaml(filename):
    stream = open(filename, 'r')

    data = yaml.load(stream, yaml.FullLoader)
    return data

$ cat pytest/test_login.py  # 测试用例
import pytest
import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from config.yaml_load import load_yaml


class Testcase:
    # 登录
    def setup(self):
        chrome_options = webdriver.ChromeOptions()
        chrome_options.add_argument("--headless")  # 无头模式
        chrome_options.add_argument("--no-sandbox")  # 沙盒模式
        chrome_options.add_argument("--incognito")  # 无痕模式
        self.driver = webdriver.Chrome(options=chrome_options)
        self.driver.get('http://ebox.wlhiot.com/login?redirect=%2Fhome')

    # 关闭浏览器
    def teardown(self):
        self.driver.quit()

    @pytest.mark.parametrize('udata', load_yaml('./data/login.yaml'))
    def test_01(self, udata):
        self.driver.find_element(By.XPATH, '//*[@id="app"]/div/form/div[1]/div/div/input').send_keys(udata['user'])
        self.driver.find_element(By.XPATH, '//*[@id="app"]/div/form/div[2]/div/div[1]/input').send_keys(udata['pwd'])
        self.driver.find_element(By.CLASS_NAME, 'el-button--primary').click()
        time.sleep(2)
        a = self.driver.current_url  # 获取点击确认后的url
        b = 'http://ebox.wlhiot.com/home'  # 正确输入密码跳转的页面
        assert a == b  # 断言,若符合预期则测试通过,不符合预期则报错


if __name__ == '__main__':
    # pytest.main(['-s', 'test_login.py', '--alluredir', './allure-results', '--clean'])
    pytest.main(['-s', 'test_login.py'])

Jenkins部署

docker run -d -p 8005:8080 --name jenkins-server \
    --shm-size="500M" \  # 由于jenkins的/dev/shm分区默认只有64M,在UI自动化测试时会因为内存不足导致页面崩溃
    -v /etc/localtime:/etc/localtime:ro \  # 时间与本机一致
    -v /usr/local/wlhiot/mount/jenkins:/var/jenkins_home \  # 数据目录,只要复制该目录即可实现数据的迁移
    -v /usr/bin/docker:/usr/bin/docker \  # 根据需要,使Jenkins也能实现docker命令
    -v /var/run/docker.sock:/var/run/docker.sock \  # 根据需要,使Jenkins也能实现docker命令
    jenkins/jenkins  # 官方镜像,原jenkins已经弃用
docker exec -it -uroot jenkins-server /bin/bash  # 使用root命令登录

权限管理

实现Jenkins用户可以使用root权限执行命令,否则测试用例无法正常运行

mv /etc/sudoers /var/jenkins_home/
vim /usr/local/wlhiot/mount/jenkins/sudoers  # 将Jenkins容器的/etc/sudoers文件迁移至/varjenkins_home/sudoers,通过宿主机添加如下两行
jenkins ALL=(ALL)   ALL
jenkins ALL=(ALL)       NOPASSWD: ALL
mv /var/jenkins_home/sudoers /etc/

python环境

总是觉得该方法太过复杂,若有更方便的方式可同作者联系wechat ID : Daihr2333

cd /usr/local/src;wget https://www.python.org/ftp/python/3.8.13/Python-3.8.13.tgz  # 若无法下载可以本机下载后存放在服务器的/usr/local/wlhiot/mount/jenkins目录,然后从容器/var/jenkins_home/目录即可找到
tar -xzvf Python-3.8.13.tgz
cd Python-3.8.13
apt-get -y install gcc automake autoconf libtool make  # 可能由于网络问题中断,记得要全部下载后再编译安装
apt-get -y install make*  # Jenkins容器的镜像是debian系,所以使用apt-get命令下载
apt-get -y install zlib*
apt-get -y install openssl libssl-dev
apt-get install sudo

cd /usr/local/src;wget https://www.openssl.org/source/openssl-1.1.1a.tar.gz  # python3.8需要高版本的openssl 
tar -zxvf openssl-1.1.1a.tar.gz
cd openssl-1.1.1a
./config --prefix=/usr/local/openssl no-zlib
make && make install 
mv /usr/bin/openssl /usr/bin/openssl.bakmv /usr/bin/openssl /usr/bin/openssl.bak
mv /usr/bin/openssl /usr/bin/openssl.bak
ln -s /usr/local/openssl/include/openssl /usr/include/openssl
ln -s /usr/local/openssl/lib/libssl.so.1.1 /usr/local/lib64/libssl.so
ln -s /usr/local/openssl/bin/openssl /usr/bin/openssl
echo "/usr/local/openssl/lib" >> /etc/ld.so.conf  # 羞辱openssl库文件的搜索路径
ldconfig -v  # 使修改后的/etc/ld.so.conf生效
openssl version  # 查看openssl版本

./configure --prefix=/usr/local/src/py3.8 --with-ssl && make && make install
ln -s /usr/local/src/py3.8/bin/python3.8 /usr/bin/python3  # 使用python3 -V验证
ln -s /usr/local/src/py3.8/bin/pip3 /usr/bin/pip3  # 使用pip3验证

pytest环境

cat /root/requirements.txt  # 也可在服务器端将文件挂载进容器
allure-pytest==2.9.45
allure-python-commons==2.9.45
async-generator==1.10
attrs==21.4.0
certifi==2022.5.18.1
cffi==1.15.0
charset-normalizer==2.0.12
cryptography==37.0.2
h11==0.13.0
idna==3.3
iniconfig==1.1.1
outcome==1.1.0
packaging==21.3
pluggy==1.0.0
py==1.11.0
pycparser==2.21
pyOpenSSL==22.0.0
pyparsing==3.0.9
PySocks==1.7.1
pytest==7.1.2
PyVirtualDisplay==3.0
PyYAML==6.0
requests==2.27.1
selenium==4.2.0
six==1.16.0
sniffio==1.2.0
sortedcontainers==2.4.0
tomli==2.0.1
trio==0.21.0
trio-websocket==0.9.2
urllib3==1.26.9
wsproto==1.1.0
pip3 install --upgrade pip  # 更新pip版本
pip3 install -Ur /root/requirements.txt  # 下载所需三方库,可根据实际需要下载

chrome及chromedriver

wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | sudo apt-key add -
sudo sh -c 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" >> /etc/apt/sources.list.d/google.list'
apt-get -y update
apt-get -y install google-chrome-stable
/usr/bin/google-chrome-stable --version  # 查看schrome版本
wget https://chromedriver.storage.googleapis.com/102.0.5005.61/chromedriver_linux64.zip
ls  # 根据chrome版本下载对应的chromedriver版本
unzip chromedriver_linux64.zip # 解压后就一个可执行文件,将可执行文件录入环境变量即可
mv chromedriver /usr/local/src/3.8/bin/
ln -s /usr/local/src/3.8/bin/chromedriver /usr/bin/chromedriver

运行测试用例

cd /var/jenkins_home/pytest  # 切换到项目目录
sudo python3 -m pytest -s --junit-xml=result.xml --alluredir /var/jenkins_home/workspace/Dir_wlh_project_test_k8s/ebox_svr_test_k8s/wlh-electric/target/allure-results --clean-alluredir
# workspace后的路径根据实际情况调整,使用该命令会生成测试用例的运行结果,能出现allure-results目录说明运行成功,该目录保存测试结果

集成(通过Jenkins-UI)

整套测试流程能跑通之后,就可以将运行测试用例的操作集成到Jenkins中以实现自动化。

插件安装

安装allure插件

点击'配置',进入'全局配置',新增Allure Commandline

修改Job配置

执行shell命令

#!/bin/bash
/bin/sleep 10  # 等服务正式部署后再进行测试,所以先等一会儿
cd /var/jenkins_home/pytest  # 切换到pytest项目路径
sudo python3 -m pytest -s --junit-xml=result.xml --alluredir /var/jenkins_home/workspace/Dir_wlh_project_test_k8s/ebox_svr_test_k8s/wlh-electric/target/allure-results --clean-alluredir
sudo chown jenkins.jenkins /var/jenkins_home/workspace/Dir_wlh_project_test_k8s/ebox_svr_test_k8s/wlh-electric/target/allure-results -R  # 修改权限,否则allure插件无法读取allure-resuluts
exit 0

调整allure配置

读取的results是以相对路径的方式,若是正常的项目一般是target/allure-results。因为我方项目是多个微服务项目集成的,所以还另加了wlh-electric作为前缀。

报告输出的路径则直接存放至相对路径的顶级目录,以我方的路径是/var/jenkins_home/workspace/Dir_wlh_project_test_k8s/ebox_svr_test_k8s/allure-reports。

实现效果