RT-Thread上使用utest+jenkins实现持续集成和自动化测试

看到一篇文章,后续工作可能会用到,转载并记录如下,原文链接:RT-Thread上使用utest+jenkins实现持续集成和自动化测试 - 掘金 (juejin.cn)

前情提要: 随着模块越来越多,测试维护成本越来越高,实现自动化便提上日程,网上关于嵌入式软件的持续集成和自动化测试的资料较少,utest是RTThread自带的测试框架,也没有接入jenkins,也没有测试报告,所以很多地方需要自己再做处理。本文记录了笔者搭建测试框架中详细的实现过程、踩过的坑和解决方法以及一些思考。

环境:RT-Thread、SCons、qemu、jenkins、utest

1. 使用jenkins实现持续集成

持续集成( Continuous integration ,简称 CI)指的是,频繁地将代码集成到主干。

持续集成的目的,就是让产品可以快速迭代,同时还能保持高质量。它的核心措施是,代码集成到主干之前必须通过自动化测试。只要有一个测试用例失败,就不能集成。

先新建一个jenkins的任务,再一个个解决问题

新建任务

构建一个自由风格的软件项目(或者可以拷贝一个scm的项目)

general和源码管理可以根据实际情况配置

构建触发器可选择定时构建或者gitlab/gerrit来触发,或者多选也可以

上图示意为周一到周五22:00定时构建

接下来build step和构建后操作就是重头戏了

build step

选择执行shell脚本

脚本内容分为几步:

  1. 获取开发代码
  2. 获取测试代码,以及mock服务
  3. 编译运行
  4. 生成html格式的测试结果报告

构建后操作

  1. 发布HTML reports
  2. 发送邮件通知

2. 问题解决

问题一:怎样执行用例

我们平时都是在整个系统编译运行之后,进入msh命令行界面进行交互,输入“utest_list","utest_run"分别查看测试用例和运行测试用例

第一个办法的灵感来源于rtthread的源码,里面找到一个utest自动化机器人,是通过python函数将命令传入

最终采用的解决方法:在/board/vexpress/arm-a9/applications/main.c中加上

#include <msh.h>

#include <finsh.h> //main函数中加入:

msh_exec("utest_run",11);

问题二:怎样结束进程

utest执行完,结束qemu是用的ctrl+A,然后再输入X,这里怎么结束进程呢

是这个问题想了我一个下午,一直没有搜到怎样退出,后来想明白了,自己怎么能结束自己呢,必须得要从外部来实现,然后碰巧看到一篇帖子求助怎么退出qemu的,发现不知道Ctrl+A+X的小伙伴一直是杀进程的,灵光一闪,那这不就是我自动化需要的方案吗!

接着就是代码实现过程:总体逻辑就是,1.启动三个进程,A进程运行,B进程等待,C进程判断log内容,2. A进程运行并将log重定向为log.txt,3.C进程判断log出现utest执行结束,便唤醒B线程来杀qemu进程

核心代码如下(仅展示方法,某些函数实现已隐去)

import threading 
import time 
import logging 
import subprocess 
import os 

logging.basicConfig(format="%(asctime)s %(threadName)s %(thread)s %(message)s",level=logging.INFO) 
event = threading.Event() 

is_executing = False 

def logrecorder(): 
    logging.info("log: logrecorder start") 
    with open('utest_log.txt', 'r') as log_file: 
        while True: 
            flag = log_file.tell() 
            line = log_file.readline() 
            if not line: 
                time.sleep(1) 
                log_file.seek(flag) 
            else: 
                #print(line) 
                if line.find('[ utest ] finished') != -1: 
                logging.info("find finished") 
                event.set() 
                break 
def test(): 
    time.sleep(3) 
    event.set() 

def run(): 
    logging.info("log: run start") 
    os.system('') 
    logging.info("log: run finish") 

def kill(): 
    logging.info("log: kill thread start") 
    event.wait() 
    os.system('ps -aux | grep qemu | grep scmbuild | grep test-memblock-unit | awk \'{print $2}\' | xargs kill -9') 
    is_executing = False 

if __name__=='__main__': 
    a = threading.Thread(name='run',target=run) 
    b = threading.Thread(name='kill',target=kill) 
    c = threading.Thread(name='logrecorder',target=logrecorder) 
    d = threading.Thread(name='test',target=test) 
    b.start() 
    a.start() 
    time.sleep(5) 
    c.start() 
 

问题三:生成测试报告

怎样生成测试报告,一目了然

因为utest没有直接生成报告的功能,所以只能自己根据log来产生结果,而且utest有一个很大问题,就是其中某个测试套件中的某条case failed了,后面的case都会跳过,所以我们目前将统计的颗粒度就设为测试套件。通过python读取log,获取需要的数值,再传到html中显示,再把html文件作为jenkins的报告输出

部分代码:

from jinja2 import Environment, FileSystemLoader 
import os 
import time 

def txt_read(): 
    return totalcase, runcase, passcase, failcase, set(faillist) 

def generate_html(body, current_time, result): 
    env = Environment(loader=FileSystemLoader('./')) 
    template = env.get_template('template.html') 
    with open("result.html", 'w+', encoding="UTF-8") as fout: 
    html_content = template.render(body=body, current_time = current_time, result=result)
    fout.write(html_content) 

def send_result(): 
    totalcase, runcase, passcase, failcase,failname = txt_read() 
    if (runcase - passcase != failcase): 
        print("Maybe something is wrong") 
    body = [] 
    if (failname): 
        result = {'ID': 1, 'total': totalcase, 'run': runcase, 'pass': passcase, 'fail':failcase, 'more' : failname} 
    else: 
        result = {'ID': 1, 'total': totalcase, 'run': runcase, 'pass': passcase, 'fail': failcase, 'more': "无"} 
    body.append(result) 
    current_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time())) 
    if(failcase == 0): 
        result = "pass" 
    else: 
        result = "fail" 
    generate_html(body, current_time, result) 

if __name__ == '__main__':
    txt_read() 
    send_result() 

 再自己写一个templete.html,每次调用python脚本即可根据templete.html生成对应的result.html,示例

<meta http-equiv="Content-Type" content="text/html;charset=utf-8"> 
<html align = 'left'> 
<h1>测试报告</h1> 
<body> 
 <div id="table0" >
     <table border= '0px ' width = "70%" cellspacing='1' cellpadding='3' align='left' bgcolor="black" >
         <tr style="color:white; font-weight: bold;text-align:left; background-color:#777;">
            <th>轮数</th> 
            <th>总用例数</th> 
            <th>执行</th> 
            <th>通过数</th> 
            <th>失败数</th> 
        </tr>
        {% for item in body %} 
        <tr align='left' bgcolor="white"> 
            <td>{{ item.ID }}</td> 
            <td>{{ item.total }}</td> 
            <td>{{ item.run }}</td> 
            <td>{{ item.pass }}</td> 
            <td>{{ item.fail }}</td> 
        </tr> 
         {% endfor %} 
      </table> 
  </div> 
  </body> 

  <body> 
  <div id="table1" class="hidden"> 
       <table border="0" width = "70%" cellspacing='1' cellpadding='3' align='left' bgcolor="black" > 
           <tr style="color:white; font-weight: bold;text-align:left; background-color:#777;"> 
                <th>测试用例</th> 
                <th>结果</th> 
                <th>备注</th> 
            </tr> 

            {% for name in failname %} 
            <tr align='left' bgcolor="white" > 
                <td>{{ name }}</td> 
                <td style = "color:FF0000"> Failed </td> 
                <td></td> 
            </tr> 
            {% endfor %} 
          </table> 
    </div> 
    </body>

问题四:邮件通知

在构建后的步骤中添加邮件报告,内容设置为html

在最下方点开

可以看到各种环境变量,能够直接用到我们这里的设置中

Project Recipient List:这里可以添加邮件地址,cc:地址可以抄送

因为我已经自己生成了测试报告,为了能把报告结合起来,采用了一下方式:

<!DOCTYPE html> 
<html> 
<head> 
<meta charset="UTF-8"> 
<title>${ENV, var="JOB_NAME"}-第${BUILD_NUMBER}次构建日志</title> 
</head> 

<body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4" offset="0"> 
    <h3>以下是Jenkins自动发送的邮件,请勿回复!</h3> 
    <div> 
    <table width="95%" cellpadding="0" cellspacing="0" style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif"> 
        <tr> 
                 <th><br /> 
             <h2>构建信息</h2> 
        </th> 
            </tr> 
        <tr> 
            <td> 
                <ul> 
                    <li>项目名称 : ${PROJECT_NAME}</li><br /> 
                    <li>触发原因: ${CAUSE}</li><br /> 
                    <li>项目 Url : <a href="${PROJECT_URL}">${PROJECT_URL}</a></li><br /> 
                    <li>工作目录 : <a href="${PROJECT_URL}ws">${PROJECT_URL}ws</a></li><br /> 
                    <li>测试报告 : <a href="${PROJECT_URL}HTML_20Report">${PROJECT_URL}HTML_20Report</a></li> 
                </ul> 
            </td> 
    </tr> 
    </table> 
    </div> 

<div> 
<table width="95%" cellpadding="0" cellspacing="0" style="font-size: 11pt; font-family: Tahoma, Arial, Helvetica, sans-serif"> 
                <tr> 
                    <th><br /> 
                <h2>测试报告</h2> 
                    </th> 
                </tr> 

            <tr> 
                <td> 
                    <div>${FILE ,path="/workspace/fw_autotest/resultBrief.html"}</div> 
                </td> 
            </tr> 

    </table> 
    </div> 
</body> 
</html>

问题五:报告优化

由于每个模块的开发和测试的需求不同,为了尽量能既一目了然又详细,所以在邮件里只是会展示结果,想要了解详细情况可以点击测试报告链接,在里面能够展示所有用例和log

点击测试报告的链接就会跳转到jenkins的html报告

其余问题:从安全性考虑,jenkins禁止了css和js的加载,所以格式会乱

解决方案:

解决jenkins显示html样式问题-CSDN博客

  • 24
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值