解决Jenkins控制台乱码与Python自动化测试CI/CD集成实战

发布时间:2026/7/7 20:02:05
解决Jenkins控制台乱码与Python自动化测试CI/CD集成实战 1. 项目概述从自动化测试到CI/CD的最后一公里搞自动化测试的朋友尤其是用Python写Web UI脚本的最终都会面临一个灵魂拷问我写的这些脚本怎么才能稳定、高效、自动地跑起来并且把结果清晰地告诉我答案就是CI/CD也就是持续集成和持续部署。这个系列走到第52篇我们终于要聊这个“最后一公里”的集大成环节了。今天我们不谈高深的理论就解决两个最实际、最接地气的问题第一怎么用Git这个版本控制工具把我们的自动化测试代码管起来让它能顺畅地进入Jenkins的流水线第二一个让无数人头疼的“玄学”问题——为什么Jenkins的控制台输出全是看不懂的乱码以及如何一劳永逸地解决它。如果你已经写好了Selenium或者Playwright的测试脚本本地跑得飞快但一到Jenkins上就各种编码报错日志里一片“锟斤拷”或者问号那么这篇文章就是为你准备的。我们将从最基础的Git操作讲起确保你的代码能正确推送到远程仓库比如GitHub、Gitee或GitLab这是Jenkins能获取到代码的前提。然后我们会深入Jenkins的“肠胃”搞清楚乱码产生的根本原因并给出从系统层面、Jenkins配置层面到Python脚本层面的全套解决方案。整个过程我会穿插我自己趟过的坑和总结的技巧目标就是让你看完就能动手彻底告别乱码让Jenkins的控制台输出变得清爽可读。2. Git核心使用为Jenkins铺平道路在CI/CD流水线中Jenkins就像一个不知疲倦的工人它的工作原料就是代码。而Git就是我们把原料代码运送到工厂Jenkins服务器的传送带。很多自动化测试项目卡在CI/CD的第一步就是因为这条“传送带”没搭建好。2.1 初始化仓库与基础提交首先确保你的自动化测试项目已经是一个Git仓库。如果还没有在你的项目根目录打开终端命令行执行git init这个命令会在当前目录创建一个隐藏的.git文件夹所有版本信息都会存储在这里。接下来我们需要告诉Git哪些文件需要被管理。对于Python自动化测试项目我们通常需要提交源代码、测试用例、配置文件但忽略虚拟环境、IDE配置和测试报告等生成文件。创建一个名为.gitignore的文件内容可以参考如下# Python __pycache__/ *.py[cod] *$py.class *.so .Python venv/ env/ .venv/ pip-log.txt pip-delete-this-directory.txt # IDE .vscode/ .idea/ *.swp *.swo # 测试报告与日志 reports/ logs/ *.log allure-results/ screenshots/ # 系统文件 .DS_Store Thumbs.db创建并配置好.gitignore后就可以进行第一次提交了# 将当前目录所有文件除.gitignore中忽略的添加到暂存区 git add . # 或者更精确地添加 # git add *.py config/ requirements.txt # 提交到本地仓库并附上说明信息 git commit -m “初始化项目添加Web UI自动化测试核心框架与用例”这里有一个关键技巧提交信息commit message一定要写清楚。好的提交信息像代码的注释能让后续维护包括Jenkins查看历史变更一目了然。建议使用“动词对象”的格式如“修复登录页面元素定位器”、“新增订单流程测试用例”。2.2 关联远程仓库与推送本地提交只是把代码存进了自家保险箱要让Jenkins能拿到必须推送到一个远程仓库。这里以GitHub为例其他平台Gitee, GitLab操作类似。首先在GitHub上创建一个新的仓库Repository名字可以叫web-ui-automation-tests。创建时不要初始化README、.gitignore或许可证文件以免和本地文件冲突。创建成功后你会获得一个仓库的HTTPS或SSH地址。接下来在本地终端将这个远程仓库地址添加为“原点”origingit remote add origin https://github.com/你的用户名/web-ui-automation-tests.git然后就可以将本地的主分支默认是main或master推送到远程了# 如果本地分支叫main git branch -M main git push -u origin main # 如果本地分支叫master git push -u origin master-u参数是--set-upstream的简写它建立了本地分支与远程分支的追踪关系。设置好后以后只需要简单的git push就能推送代码。注意第一次推送可能会要求输入GitHub的用户名和密码或Token。现在GitHub已禁用密码验证你需要使用个人访问令牌Personal Access Token。在GitHub设置中生成一个具有repo权限的Token用它来代替密码。2.3 面向CI/CD的Git工作流建议对于自动化测试项目我推荐使用一种简单明了的分支策略这能让Jenkins的构建触发逻辑更清晰。main/master分支保护分支存放稳定、可随时用于生产的测试代码。任何向该分支的合并通常通过Pull Request都会触发Jenkins的完整回归测试流水线。develop分支开发分支用于集成日常开发的新测试用例或框架改进。可以配置Jenkins对该分支的每次推送都执行一轮测试但可能不包含全部耗时的用例。功能分支feature/*当你要开发一组新的测试用例或一个大的框架功能时从develop分支切出例如feature/login-test。开发完成后合并回develop分支。可以在功能分支上配置Jenkins进行快速构建验证。基本的操作流程如下# 1. 基于develop创建功能分支 git checkout develop git pull origin develop git checkout -b feature/add-checkout-flow # 2. 在新分支上开发、提交代码... git add . git commit -m “新增购物车结算流程测试用例” # 3. 开发完成推送到远程 git push origin feature/add-checkout-flow # 4. 在GitHub/GitLab上创建Pull Request请求合并到develop # 5. 代码审查后合并删除远程功能分支这种模式的好处是你可以为main和develop分支在Jenkins中配置不同的任务。例如main分支的构建任务执行全量测试并生成正式报告develop分支的任务则执行核心冒烟测试速度更快。3. Jenkins控制台乱码问题深度解析代码成功推送到仓库后下一步就是在Jenkins中创建任务来拉取并执行它。然而很多人在第一步就遇到了“拦路虎”构建控制台输出中所有中文字符都变成了乱码这让你根本无法调试脚本失败的原因。3.1 乱码根源编码的“鸡同鸭讲”乱码的本质是编码Encoding和解码Decoding使用了不同的字符集规则。在Jenkins的流水线中涉及多个环节任何一个环节的编码不统一都会导致乱码。源文件编码你的Python测试脚本文件本身是以什么编码保存的现在普遍推荐使用UTF-8。你可以在VSCode或PyCharm的右下角看到文件编码。如果文件是GBK编码而其他环节用UTF-8去读就会出错。操作系统本地编码Jenkins服务器运行的操作系统有一个默认的本地编码Locale。例如一些旧的或特定优化的Linux系统可能默认是en_US.UTF-8或zh_CN.GBK。Jenkins进程会继承这个环境。Jenkins JVM编码Jenkins本身是一个Java应用运行在Java虚拟机JVM上。JVM有自己默认的字符集如果没有特别指定它可能会使用操作系统的默认编码但有时行为不一致。Python解释器编码当Jenkins调用Python来执行你的脚本时Python解释器也有自己的标准输出/错误流的编码这通常由环境变量如PYTHONIOENCODING或操作系统环境决定。终端/控制台编码最终Jenkins将构建日志输出到网页控制台浏览器和Jenkins的页面编码需要能正确显示这些字符。当这五者的编码不一致时乱码就产生了。最常见的情况是你的Python脚本文件是UTF-8脚本中的print(“测试开始”)也是UTF-8字符串。但在一个默认Locale为C或POSIX即ASCII的Jenkins环境中Python解释器可能以ASCII编码去输出遇到中文就抛异常或转换成乱码或者JVM以ISO-8859-1读取了UTF-8的字节流再显示到网页上就变成了“测试”。3.2 系统级与Jenkins级编码检查与设置解决问题的第一步是诊断。我们可以通过一些命令来检查Jenkins所在系统的编码环境。登录到Jenkins服务器如果是Docker安装的需要进入容器执行以下命令# 查看当前系统的语言和编码环境 locale # 重点关注LC_ALL, LC_CTYPE, LANG这几个变量。理想状态应该是类似zh_CN.UTF-8或en_US.UTF-8。 # 查看Java虚拟机的默认字符集 java -XshowSettings:properties -version 21 | grep file.encoding # 输出应该是类似file.encoding UTF-8如果locale命令的输出中LC_ALL、LC_CTYPE或LANG不是UTF-8相关的值那么就需要修改系统环境。对于Ubuntu/Debian系统可以安装中文语言包并设置sudo apt-get update sudo apt-get install -y locales sudo locale-gen zh_CN.UTF-8 sudo update-locale LANGzh_CN.UTF-8 LC_ALLzh_CN.UTF-8 # 修改后需要重启服务器或重新登录会话生效对于使用Docker镜像运行Jenkins的情况更佳实践是在构建自己的Jenkins镜像时就设置好环境变量。可以在Dockerfile中加入FROM jenkins/jenkins:lts USER root RUN apt-get update apt-get install -y locales \ locale-gen zh_CN.UTF-8 \ update-locale LANGzh_CN.UTF-8 ENV LANG zh_CN.UTF-8 ENV LANGUAGE zh_CN:zh ENV LC_ALL zh_CN.UTF-8 USER jenkins接下来配置Jenkins本身。Jenkins有一个全局的“文件编码”默认设置但更重要的是传递给JVM的参数。检查Jenkins系统设置进入“Manage Jenkins” - “System”找到“Global properties”部分。可以勾选“Environment variables”添加一个键为LANG值为zh_CN.UTF-8或en_US.UTF-8的变量。但这主要影响Shell步骤的环境。修改JVM启动参数关键步骤这是解决乱码最有效的方法之一。你需要找到Jenkins的启动配置文件。对于Linux系统服务配置文件通常在/etc/default/jenkins或/etc/sysconfig/jenkins。找到JAVA_ARGS或JENKINS_JAVA_OPTIONS在其中添加-Dfile.encodingUTF-8 -Dsun.jnu.encodingUTF-8。对于Docker运行在docker run命令中添加环境变量例如-e JAVA_OPTS-Dfile.encodingUTF-8 -Dsun.jnu.encodingUTF-8。对于Tomcat部署修改Tomcat的catalina.sh或catalina.bat在JAVA_OPTS中添加上述参数。修改完成后必须重启Jenkins服务才能生效。3.3 在Pipeline与Python脚本中强制指定编码即使系统层面配置好了为了万无一失我们还需要在Pipeline任务和Python脚本内部做好防御性编码设置。在Jenkins Pipeline脚本Jenkinsfile中我们可以在sh或bat步骤中显式地设置环境变量pipeline { agent any environment { // 设置Pipeline内全局的环境变量 LANG ‘zh_CN.UTF-8’ PYTHONIOENCODING ‘utf-8’ } stages { stage(‘Test’) { steps { script { // 或者在具体的sh步骤中设置 sh ‘’’ export LANGzh_CN.UTF-8 export PYTHONIOENCODINGutf-8 python -m pytest your_test_suite.py -v ‘’’ } } } } }重点在于PYTHONIOENCODINGutf-8这个环境变量。它直接告诉Python解释器标准输入、输出和错误的编码都使用UTF-8这是解决Python输出乱码的利器。在你的Python自动化测试脚本中也应该在文件开头显式声明编码并且对文件操作、网络请求等可能涉及编码的地方保持警惕#!/usr/bin/env python3 # -*- coding: utf-8 -*- Web UI自动化测试主模块 此文件采用UTF-8编码 import sys import io # 强制标准输出使用UTF-8编码另一道保险 sys.stdout io.TextIOWrapper(sys.stdout.buffer, encoding‘utf-8’) import pytest from selenium import webdriver def test_login(): print(“[INFO] 开始执行登录测试...”) # 现在这个中文字符串应该能正确输出了 # ... 你的测试逻辑对于使用logging模块记录日志的情况同样需要配置编码import logging logging.basicConfig( levellogging.INFO, format‘%(asctime)s - %(name)s - %(levelname)s - %(message)s’, handlers[ logging.FileHandler(‘execution.log’, encoding‘utf-8’), # 指定文件编码 logging.StreamHandler() # 输出到控制台 ] ) logger logging.getLogger(__name__) logger.info(“配置日志完成编码为UTF-8”)4. 构建可复现的Jenkins Pipeline任务解决了编码问题我们就可以安心地构建一个健壮的Jenkins任务了。这里以一个经典的Pipeline任务为例展示如何集成Git和Python自动化测试。4.1 创建Pipeline项目与基础配置在Jenkins首页点击“新建Item”输入任务名称例如“Web-UI-AutoTest-Pipeline”选择“Pipeline”类型。在项目配置页面我们需要关注几个关键部分General可以添加描述或使用“参数化构建”来动态传入测试环境地址、浏览器类型等。Build Triggers设置构建触发器。最常用的是“GitHub hook trigger for GITScm polling”或“Poll SCM”。前者需要你在GitHub仓库的Webhook中配置Jenkins的URL实现代码一推送就自动构建后者是Jenkins定期去检查仓库是否有更新。Poll SCM的日程表语法类似Cron例如H/5 * * * *表示每5分钟检查一次。对于测试任务频率可以设高一些。Pipeline这是核心。选择“Pipeline script from SCM”。这样我们的流水线定义Jenkinsfile就可以跟代码一起存放在Git仓库中实现“Pipeline as Code”。SCM选择Git。Repository URL填写你的Git仓库地址如https://github.com/你的用户名/web-ui-automation-tests.git。Credentials添加访问仓库的凭证用户名密码或SSH密钥。Branches to build指定要监听的分支例如*/main,*/develop。Script Path默认为Jenkinsfile。这意味着Jenkins会在你仓库的根目录寻找名为Jenkinsfile的文件来定义流水线。4.2 编写Jenkinsfile定义完整流水线在你的自动化测试项目根目录创建一个名为Jenkinsfile的文件无后缀。这是一个用Groovy DSL写的脚本文件。下面是一个包含环境准备、测试执行、结果收集的完整示例pipeline { agent any // 指定在任何可用代理上运行 environment { // 全局环境变量解决乱码问题 LANG ‘en_US.UTF-8’ PYTHONIOENCODING ‘utf-8’ // 项目相关变量 PROJECT_NAME ‘web-ui-automation’ TEST_REPORT_DIR ‘${WORKSPACE}/reports’ } stages { stage(‘Checkout’) { steps { echo ‘开始从Git仓库拉取代码...’ checkout scm // 这是一个内置步骤会拉取触发此次构建的对应分支代码 sh ‘git log -1 --oneline’ // 打印最近一次提交信息便于追溯 } } stage(‘Prepare Environment’) { steps { echo ‘准备Python测试环境...’ sh ‘’’ python --version pip --version # 建议使用虚拟环境隔离依赖 python -m venv venv . venv/bin/activate pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple ‘’’ } } stage(‘Run Tests’) { steps { echo ‘开始执行Web UI自动化测试...’ sh ‘’’ . venv/bin/activate # 设置环境变量确保WebDriver如ChromeDriver路径等 export PATH$PATH:${WORKSPACE}/drivers # 执行pytest测试生成多种格式报告 pytest tests/ \ -v \ --html${TEST_REPORT_DIR}/report.html \ --self-contained-html \ --junitxml${TEST_REPORT_DIR}/junit-report.xml \ --alluredir${TEST_REPORT_DIR}/allure-results \ --capturesys \ # 确保输出被捕获 -o junit_familyxunit2 echo “测试执行完毕退出码为: $?” ‘’’ } } stage(‘Archive Report’) { steps { echo ‘归档测试报告和日志...’ // 归档HTML报告使其可在Jenkins界面直接访问 publishHTML(target: [ reportName: ‘HTML Report’, reportDir: “${TEST_REPORT_DIR}”, reportFiles: ‘report.html’, keepAll: true, alwaysLinkToLastBuild: true ]) // 发布JUnit格式报告Jenkins可以解析并展示测试趋势图 junit testResults: “${TEST_REPORT_DIR}/junit-report.xml”, allowEmptyResults: true // 如果使用Allure报告可以安装Allure插件并在此发布 // allure includeProperties: false, jdk: ‘’, results: [[path: “${TEST_REPORT_DIR}/allure-results”]] } post { always { echo ‘清理临时文件...’ sh ‘rm -rf venv || true’ // 清理虚拟环境|| true确保命令失败不影响整体 archiveArtifacts artifacts: “${TEST_REPORT_DIR}/**”, fingerprint: true } } } } post { always { echo “Pipeline [${PROJECT_NAME}] 执行结束。” // 可以在这里添加邮件通知、钉钉/企业微信机器人通知等 // emailext body: “构建 ${env.BUILD_NUMBER} 状态: ${currentBuild.currentResult}\n 查看详情: ${env.BUILD_URL}”, subject: “Jenkins构建通知: ${env.JOB_NAME}”, to: ‘teamexample.com’ } failure { echo ‘本次构建失败’ } success { echo ‘本次构建成功’ } } }这个Jenkinsfile定义了一个四阶段的流水线并设置了后置处理步骤。将它与你的代码一起提交并推送到Git仓库的对应分支如main。当Jenkins检测到该分支有更新时就会自动拉取这个Jenkinsfile并按照它定义的过程执行。4.3 关键插件安装与配置为了让上述流水线正常工作并拥有更好的体验你需要在Jenkins的“Manage Jenkins” - “Manage Plugins”中安装以下常用插件PipelinePipeline插件组是基础。Git提供Git集成支持。HTML Publisher用于发布和展示HTML格式的测试报告如pytest-html生成的报告。JUnit用于解析和展示JUnit格式的XML测试报告生成历史趋势图。Allure Jenkins Plugin如果你使用Allure生成更美观的测试报告需要此插件。Email Extension Plugin用于发送更灵活美观的构建通知邮件。安装完插件后可能需要在系统配置中设置相关路径例如Allure的命令行工具路径。5. 进阶技巧与深度避坑指南掌握了基础搭建后还有一些进阶技巧和深坑需要注意这些往往是决定你的CI/CD流水线是否稳健、高效的关键。5.1 使用Docker容器作为构建环境直接在Jenkins代理节点上安装Python、浏览器、WebDriver等依赖容易造成环境污染和不一致。使用Docker容器可以完美解决这个问题。你可以指定一个包含所有测试依赖的Docker镜像作为构建环境。在Jenkinsfile中可以这样修改agent部分pipeline { agent { docker { image ‘python:3.9-slim’ // 使用官方Python镜像 args ‘-v /path/to/local/drivers:/opt/drivers’ // 将本地的WebDriver挂载到容器内 reuseNode true // 尽可能重用同一个宿主机节点 } } stages { stage(‘Test’) { steps { sh ‘’’ # 容器内已有一个干净的Python环境 pip install -r requirements.txt # 假设WebDriver已通过卷挂载到/opt/drivers export PATH$PATH:/opt/drivers pytest tests/ ‘’’ } } } }对于Web UI测试你甚至可以使用集成了浏览器和WebDriver的镜像如selenium/standalone-chrome。但需要注意这类镜像通常不包含Python你可能需要基于它构建自己的镜像或者使用docker-compose在流水线中启动Selenium Grid服务。5.2 并行测试与资源优化当测试用例数量庞大时串行执行会非常耗时。利用Jenkins Pipeline的parallel指令可以将测试套件拆分并行执行大幅缩短反馈时间。stage(‘Parallel Tests’) { parallel { stage(‘Module A Tests’) { steps { sh ‘pytest tests/module_a/’ } } stage(‘Module B Tests’) { steps { sh ‘pytest tests/module_b/’ } } stage(‘API Tests’) { steps { sh ‘pytest tests/api/’ } } } }注意事项并行测试需要处理好测试环境的隔离比如使用不同的用户会话、临时数据库或者通过测试框架的插件如pytest-xdist来管理进程级隔离避免用例间相互干扰。5.3 依赖管理与缓存提速每次构建都重新下载pip包非常耗时。Jenkins的Pipeline Utility Steps插件提供了readJSON、writeJSON等工具但更常用的是利用Docker的层缓存或者在Jenkins代理节点上配置pip缓存。对于非Docker环境可以在Prepare Environment阶段加入缓存逻辑stage(‘Prepare Environment’) { steps { dir(“${env.HOME}/.cache/pip”) { // 检查缓存是否存在或者使用Jenkins的缓存机制需要插件 } sh ‘’’ python -m pip install --upgrade pip # 使用国内镜像源加速并利用pip的缓存机制 pip install -r requirements.txt --cache-dir ${env.HOME}/.cache/pip -i https://mirrors.aliyun.com/pypi/simple/ ‘’’ } }更现代的做法是使用pipenv或poetry这类工具管理依赖和虚拟环境它们有更好的锁定文件和缓存机制。5.4 乱码问题终极排查清单如果按照前面的步骤配置后乱码问题依然存在请按照以下清单进行终极排查确认源文件编码用file -i your_script.py命令Linux或编辑器底部状态栏确认脚本文件编码为UTF-8。如果不是批量转换find . -name “*.py” -exec iconv -f GBK -t UTF-8 {} -o {}.utf8 \; -exec mv {}.utf8 {} \;操作前备份。验证Jenkins JVM编码在Pipeline中增加一个步骤sh ‘java -XshowSettings:properties -version 21 | grep file.encoding’查看构建时的实际编码。检查Shell环境在Pipeline的sh步骤中首先执行locale; echo $LANG; echo $PYTHONIOENCODING打印出所有环境变量确认是否生效。Python内部诊断在测试脚本最开始添加诊断代码import sys, locale, codecs print(f“Python默认编码: {sys.getdefaultencoding()}”) print(f“标准输出编码: {sys.stdout.encoding}”) print(f“文件系统编码: {sys.getfilesystemencoding()}”) print(f“Locale编码: {locale.getpreferredencoding()}”) # 尝试直接写入标准输出缓冲区 sys.stdout.buffer.write(‘[DEBUG] 直接写入buffer测试\n’.encode(‘utf-8’))Jenkins控制台输出编码在Jenkins系统管理 - “系统设置”中搜索“编码”检查“Default encoding for files and streams”是否为空或设置为UTF-8。同时检查你的浏览器编码是否自动检测或强制设置为UTF-8。日志文件对比让脚本将关键日志同时输出到控制台和一个明确以UTF-8编码打开的文件中。构建完成后下载这个日志文件用支持UTF-8的文本编辑器如VSCode, Notepad打开查看。如果文件内容正确而控制台乱码问题就锁定在Jenkins的显示环节如果文件也乱码问题则出在Python执行环节。我个人的经验是90%的乱码问题可以通过“设置系统Locale为UTF-8” “在Jenkins JVM参数中添加-Dfile.encodingUTF-8” “在Pipeline中设置PYTHONIOENCODINGutf-8”这三板斧解决。剩下的10%多半是某些第三方库或底层系统调用没有正确处理编码这就需要针对性地去调试那个特定的库了。记住保持整个链路编码的一致性是解决乱码问题的黄金法则。