zoukankan      html  css  js  c++  java
  • 在稳定性测试中,将测试结果持续填加进入html报告

          公司需要设计一个稳定性测试,就是一直持续的跑不同的用例,直到人为停止,用例基本完成,基本框架思路就是随机选择一个testcase,跑完后输出结果。但存在一个问题,现在的unittest或nose测试报告都是测完所有case后再输出html报告,再次运行,又生成新的,没法再原来的报告中再填加结果。

          就这样问题,基本解决思路就是直接写个生成html报告的模块,然后再次每次结果加入。正好最近在看tempest的东西,里面有个这样的模块,那就不重复造轮子了,直接拿过来用吧。

         先看看生成html_log.py文件

        

    import shutil
    
    
    
    try:
        import xml.etree.cElementTree as ET
    except Exception:
        import xml.etree.ElementTree as ET
    
    TYPE_OK = 0
    TYPE_ERROR = -1
    TYPE_FAIL = -2
    TYPE_SKIP = -3
    
    
    class InfoParser(object):
    
        def __init__(self, file_path, info):
            self.file_path = file_path
            self.info = info
    
        def get_state(self):
            if self.info.find('... ok') != -1:
                return TYPE_OK
            elif self.info.find('... ERROR') != -1:
                return TYPE_ERROR
            elif self.info.find('... FAIL') != -1:
                return TYPE_FAIL
            elif self.info.find('... SKIP') != -1:
                return TYPE_SKIP
    
        def get_detail(self):
            if self.get_state() == 0:
                return ''
            else:
                offset = self.info.find('Traceback')
                if offset != -1:
                    temp = self.info[offset:]
                    return temp
                else:
                    return ''
    
        def get_class_name(self):
            temp = self.get_testcase_name()
            offset = temp.rfind('.')
            if offset != -1:
                temp = temp[0: offset]
                return temp
            else:
                return ''
    
        def get_testcase_name(self):
            offset = self.info.find(' ...')
            if offset != -1:
                temp = self.info[0: offset]
                return temp
            return ''
    
        def create_new_overview_node(self, root, state, class_name):
            new_node = ET.Element('tr')
            root.insert(len(root.getchildren()) - 1, new_node)
            # testcase name
            sub_node = ET.SubElement(new_node, 'td')
            sub_node.text = class_name
    
            for x in range(5):
                sub_node = ET.SubElement(new_node, 'td')
                sub_node.text = '0'
    
            return new_node
    
        def add_overview_node_detail(self, item, state):
            item[5].text = str(int(item[5].text) + 1)
            if state == TYPE_FAIL:
                item[1].text = str(int(item[1].text) + 1)
                item[1].set('class', 'failed')
            elif state == TYPE_ERROR:
                item[2].text = str(int(item[2].text) + 1)
                item[2].set('class', 'failed')
            elif state == TYPE_SKIP:
                item[3].text = str(int(item[3].text) + 1)
            elif state == TYPE_OK:
                item[4].text = str(int(item[4].text) + 1)
    
        def add_to_overview(self, root, state, class_name):
            iter = root.getchildren()
            for item in iter:
                if item[0].text == class_name:
                    self.add_overview_node_detail(item, state)
                    # handle total
                    total_item = root[len(root.getchildren()) - 1]
                    self.add_overview_node_detail(total_item, state)
                    return
    
            new_item = self.create_new_overview_node(root, state, class_name)
            self.add_overview_node_detail(new_item, state)
            # handle total
            total_item = root[len(root.getchildren()) - 1]
            self.add_overview_node_detail(total_item, state)
    
        def add_to_failure(self, root):
            new_item = ET.SubElement(root, 'section')
            # name
            sub_item = ET.SubElement(new_item, 'h3')
            sub_item.text = self.get_testcase_name()
            # details
            sub_item = ET.SubElement(new_item, 'div')
            sub_item.set('class', 'test-details')
            detail_sub_item = ET.SubElement(sub_item, 'h4')
            detail_sub_item.text = 'Detail'
            detail_sub_item = ET.SubElement(sub_item, 'pre')
            detail_sub_item.text = self.get_detail()
    
        def add_to_all_tests(self, root, state):
            new_item = ET.SubElement(root, 'li')
            sub_item = ET.SubElement(new_item, 'a')
            sub_item.text = self.get_testcase_name()
            if state == TYPE_FAIL or state == TYPE_ERROR:
                sub_item.set('class', 'failed')
            else:
                sub_item.set('class', 'success')
    
        def write_log(self):
            ret = self.get_state()
    
            tree = ET.parse(self.file_path)
            root = tree.getroot()
    
            # add overview
            self.add_to_overview(
                root.find('body').find('overview').find('section').find('table'),
                ret, self.get_class_name())
    
            # add fail view
            if ret == TYPE_FAIL or ret == TYPE_ERROR:
                self.add_to_failure(
                    root.find('body').find('failure_details').
                    find('section').find('div'))
    
            # add all tests
            self.add_to_all_tests(
                root.find('body').find('all_tests').find('section').find('ul'),
                ret)
    
            tree.write(self.file_path)
    
    
    def create_log_from_file(path, souce):
        shutil.copyfile(souce, path)
    
    
    def add_log(path, info):
        info_parser = InfoParser(path, info)
        info_parser.write_log()
    
    
    def format_testrunner_info(test, info, state):
        result = ''
        # handle name
        name = str(test)
        offset_b = name.find('(')
        offset_e = name.find(')')
        testcase_name = 'no name'
        if offset_b != -1 and offset_e != -1:
            testcase_name = name[offset_b + 1: offset_e]
            offset_e = name.find(' (')
            if offset_e != -1:
                testcase_name += '.'
                testcase_name += name[0: offset_e]
        result = testcase_name
    
        if state == TYPE_OK:
            result += ' ... ok
    
    '
        elif state == TYPE_ERROR:
            result += ' ... ERROR
    
    '
        elif state == TYPE_FAIL:
            result += ' ... FAIL
    
    '
        elif state == TYPE_SKIP:
            result += ' ... SKIP
    
    '
    
        result += info
    
        return result
    
    
    def add_testrunner_log(path, result, test_name):
        # success
        if result.wasSuccessful():
            info = format_testrunner_info(test_name, 'Ran 1 test', TYPE_OK)
            #info = format_testrunner_info(name,'Ran 1 test',TYPE_OK)
            add_log(path, info)
    
        # fail
        for test, err in result.failures:
            info = format_testrunner_info(test, err, TYPE_FAIL)
            add_log(path, info)
    
        # error
        for name, err in result.errors:
            info = format_testrunner_info(name, err, TYPE_ERROR)
            add_log(path, info)
    
        # skip
        for test, reason in result.skipped:
            info = format_testrunner_info(test, reason, TYPE_SKIP)
            add_log(path, info)
    

      使用非常简单,使用对应的空报告模板,使生成的结果调用add_testrunner_log写入空模板中,最后就可以持续生成报告了

    空模板见下面的html代码,copy下来后存成html文件即可使用

    <!DOCTYPE html>
    <html>
    <head>
        <title>Unit Test Report</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
    
    <style>
    body {
        font-family: Calibri, "Trebuchet MS", sans-serif;
    }
    * {
        word-break: break-all;
    }
    table, td, th, .dataid {
        border: 1px solid #aaa;
        border-collapse: collapse;
        background: #fff;
    }
    section {
        background: rgba(0, 0, 0, 0.05);
        margin: 2ex;
        padding: 1ex;
        border: 1px solid #999;
        border-radius: 5px;
    }
    h1 {
        font-size: 130%;
    }
    h2 {
        font-size: 120%;
    }
    h3 {
        font-size: 100%;
    }
    h4 {
        font-size: 85%;
    }
    h1, h2, h3, h4, a[href] {
        cursor: pointer;
        color: #0074d9;
        text-decoration: none;
    }
    h3 strong, a.failed {
        color: #ff4136;
    }
    .failed {
        color: #ff4136;
    }
    a.success {
        color: #3d9970;
    }
    pre {
        font-family: 'Consolas', 'Deja Vu Sans Mono',
                     'Bitstream Vera Sans Mono', 'Monaco',
                     'Courier New', monospace;
    }
    
    .test-details,
    .traceback {
        display: none;
    }
    section:target .test-details {
        display: block;
    }
    
    </style>
    </head>
    <body>
        <overview>
            <h1>Overview</h1>
            <section>
                <table>
                    <tr>
                        <th>Class</th>
                        <th class="failed">Fail</th>
                        <th class="failed">Error</th>
                        <th>Skip</th>
                        <th>Success</th>
                        <th>Total</th>
                    </tr>
                    <tr>
                    <td><strong>Total</strong></td>
                    <td>0</td>
                    <td>0</td>
                    <td>0</td>
                    <td>0</td>
                    <td>0</td>
                </tr>
                </table>
            </section>
        </overview>
        <failure_details>
            <h1>Failure details</h1>
                <section>
                    <h2>Failure details</h2>
                    <div>
                    </div>
                </section>
        </failure_details>
        <all_tests>
            <h1>All tests</h1>
                <section>
                    <h2>all tests</h2>
                    <ul>
                    </ul>
                </section>
        </all_tests>
    </body>
    <script>
        Array.prototype.forEach.call(document.querySelectorAll('h1, h2, h3, h4'), function(el) {
            el.addEventListener('click', function() {
                el.nextElementSibling.style.display = document.defaultView.getComputedStyle(el.nextElementSibling).display == 'none' ? 'block' : 'none';
            })
        })
    </script>
    View Code

    使用unittest写个示范代码如下:

    import unittest
    import time
    import sys
    import html_log
    import os
    import re
    import random
    
    
    class test(unittest.TestCase):
        def setUp(self):
            pass
        
        def test_0001(self):
            
            assert 1==1
        
        def test_0002(self):
            
            assert 2==2
    
    if __name__=='__main__':
        suite=unittest.TestLoader().loadTestsFromTestCase(test)
        testcases=list()
        listcasedir='.'
        testunit=unittest.TestSuite()
      
        
        #选择case
        for test_case in suite:
            print test_case
            f=re.match("(test_.*) (__main__.test)",str(test_case))
            tt=f.group(1)
            testcases.append(test_case)
        
        test = random.choice(testcases)
        mySuite = unittest.TestSuite()
        mySuite.addTest(test)
        result = unittest.TextTestRunner().run(mySuite)
        
        #这里xx.html就是对应的空模板
    if not os.path.exists('test_aa.html'): html_log.create_log_from_file('test_aa.html', 'xx.html')
    #将结果持续加入到对应的html报告中 print test html_log.add_testrunner_log('test_aa.html', result, test)

     结果如下,测试一直在进行,结果就一直会持续输入

  • 相关阅读:
    POJ 1789
    南华大学 复读机(并查集)
    C
    F
    POJ 1988 Cube Stacking
    并查集(一)
    把采集到的数据发送到一个Google Docs或者Google Form上 这个网站提供了参考和例子
    几种空气颗粒物和空气质量传感器
    整流桥
    STM32 中的CEC
  • 原文地址:https://www.cnblogs.com/landhu/p/6284873.html
Copyright © 2011-2022 走看看