python unittest 运行失败后重试

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python unittest 运行失败后重试相关的知识,希望对你有一定的参考价值。

  最近为了实现自动化测试case运行失败后自动重试到处求教,自己研究了两三天以失败告终,最后在网上发现有大神重写了suite中的run方法说可以实现,但是不太适用我的项目,最终通过重写run_tests.py文件配合重写后的run方法实现了运行失败后重试。

run方法 源代码出处:http://blog.csdn.net/hqzxsc2006/article/details/50349664

 

下面是针对自己项目做的修改(关于最后邮件发送的就不说了):

suite.py

# -*- coding:utf-8 -*-
import unittest,time
from unittest.suite import _isnotsuite


class Suite(unittest.TestSuite):
    def run(self, result, debug=False):
        fail_count = 1
        class_num = 1
        topLevel = False
        if getattr(result, _testRunEntered, False) is False:
            result._testRunEntered = topLevel = True

        for test in self:
            case_num = 1
            if result.shouldStop:
                break
            success_flag = True
            while success_flag:
                if _isnotsuite(test):
                    self._tearDownPreviousClass(test, result)
                    self._handleModuleFixture(test, result)
                    self._handleClassSetUp(test, result)
                    result._previousTestClass = test.__class__
                    if (getattr(test.__class__, _classSetupFailed, False) or
                            getattr(result, _moduleSetUpFailed, False)):
                        if class_num > fail_count:
                            success_flag = False
                        else:
                            time.sleep(5)
                            result._previousTestClass = None
                            print %s Retrying init for %s times... % (test.__class__, class_num)
                            class_num += 1
                        continue

                if not debug:
                    test(result)
                    print 1
                else:
                    test.debug()

                if result.result[-1][0] == 1 or result.result[-1][0] == 2:  # 1为Failed,2为Error
                    if case_num > fail_count:
                        success_flag = False
                    else:
                        print %s is Failed ! Retrying %s times... % (test, case_num)
                        case_num += 1
                else:
                    success_flag = False

            if topLevel:
                self._tearDownPreviousClass(None, result)
                self._handleModuleTearDown(result)
                result._testRunEntered = False
        return result

    def removeTest(self, test):
        self._tests.remove(test)

新写了一个removeTest()方法用于移除测试用例集中的用例

runtests.py

# -*- coding:utf-8 -*-
import unittest,time,settings
from utilities.send_mail import send_mail,new_report
import HTMLTestRunner,suite,os
from BeautifulSoup import BeautifulSoup


def get_result_html(file_dir):
    L = []
    for root, dirs, files in os.walk(file_dir):
        for file in files:
            if os.path.splitext(file)[1] == .html:
                L.append(os.path.join(root, file))
    return L


def get_result_text():
    name = get_result_html(settings.RESULT_HTML_DIR)[-1]
    htmlfile = open(name, r)
    htmlpage = htmlfile.read()
    soup = BeautifulSoup(htmlpage)

    pass_div = soup.findAll(tr, attrs={class: passClass})
    pass_case_num = str(len(pass_div))

    file_obj = open(settings.RESULT_TEXT_DIR + /test_result.txt, wb+)
    file_obj.writelines(API TEST RESULT!)
    file_obj.writelines(\\n\\n\\n\\n\\n\\n\\n\\n\\n)
    file_obj.writelines(SUCCESS: + pass_case_num)
    file_obj.writelines(\\n\\n\\n\\n\\n\\n\\n\\n\\n)
    file_obj.writelines(FAILED: + str(int(len(case_name_list)) - int(pass_case_num)))
    file_obj.writelines(\\n\\n\\n\\n\\n\\n\\n\\n\\n)
    file_obj.writelines(START_TIME: + str(start_time))
    file_obj.writelines(\\n\\n\\n\\n\\n\\n\\n\\n\\n)
    file_obj.writelines(END_TIME: + str(end_time))
    file_obj.close()


if __name__ == __main__:
    start_time = time.strftime("%Y-%m-%d %H:%M:%S")
    test_dir = settings.API_TEST_CASE_DIR
    suite = suite.Suite()
    file_name = ./result/ + time.strftime("%Y_%m_%d_%H_%M_%S") + _ + settings.RESULT_FILE_NAME
    fp = open(file_name, wb+)
    runner = HTMLTestRunner.HTMLTestRunner(stream=fp, title=settings.RESULT_TITLE,
                                               description=settings.RESULT_DESCRIPTION, verbosity=2)
    for case in test_dir:
        test_case = unittest.defaultTestLoader.discover(case,pattern=test_*,top_level_dir=os.path.abspath(./test_case/api_test_case/))
        case_name_list = []

        for x in [i._tests for i in test_case]:
            if not len(x) == 0:
                if len(x) == 1:
                    tds1 = x[0]
                    if not len(tds1._tests) == 0:
                        for y in tds1._tests:
                            case_name_list.append(y)

                elif len(x) == 2:
                    tds1 = x[0]
                    if not len(tds1._tests) == 0:
                        for y in tds1._tests:
                            case_name_list.append(y)
                    tds2 = x[1]
                    if not len(tds2._tests) == 0:
                        for y in tds2._tests:
                            case_name_list.append(y)

        for case_one in test_case._tests[0]._tests[1]:
            suite.addTest(case_one)
            runner.run(suite)
            suite.removeTest(case_one)
    fp.close()
    end_time = time.strftime("%Y-%m-%d %H:%M:%S")
    time.sleep(0.5)
    get_result_text()

    if not settings.ENV == dev:
        new_report = new_report(settings.RESULT_TEXT_DIR)
        time.sleep(0.5)
        send_mail(new_report)

因项目中case分类比较复杂,中间用了多个for循环获取case,实现的效果是,单个case添加到测试用例集里面,执行完之后,移除这个case,再添加下一个case。

缺点就是生成的html报告不太理想,无法汇总全部case的总结果。

技术分享

最终的总结果是通过BeautifulSoup获取html报告中成功的用例个数,再用总用例数减去成功用例数得到失败用例数,和总运行时长,汇总在test_result.txt中,再通过邮件发送运行情况报告。

以上是关于python unittest 运行失败后重试的主要内容,如果未能解决你的问题,请参考以下文章

rabbitmq~消息失败后重试达到 TTL放到死信队列(事务型消息补偿机制)

打开QT_Creator提示计算机丢失python36.dll,请重新安装程序后重试

聊聊数据库乐观锁和悲观锁,乐观锁失败后重试

Angular Http 请求出错后重试

Spring Kafka - 事务回滚后重试时,通过侦听器容器事务发布消息和提交记录偏移失败

使 wget 在 3XX 重定向后重试原始 URL