自动化工具 python 的 unittest 测试框架中的测试依赖怎么解决呢

zhang · 2019年01月10日 · 最后由 zhang 回复于 2019年01月11日 · 4260 次阅读

在 python 的自动化测试过程中,使用了 unittest 的测试框架,每个用例可以单独执行,用例之间没有依赖关系。
但是在实际业务过程中,由于业务逻辑较复杂,一般用例之间是有依赖关系的。比如从用户注册到用户下单支付这个流程过程中,只有用户注册账户成功了,后面的所有的测试用例才有意义,一旦注册失败,后面的所有的测试用例都是需要跳过的。所以当前想解决这个问题。查看了 testng 框架,TestNG 依赖测试使用了 dependsOnMethods ,如下图:

这样在 TestNG 中就可以解决用例之间的依赖问题。
在 python 的测试框架中,有没有类似的方法或库,各位是怎么解决的呢 ,谢谢了

共收到 8 条回复 时间 点赞

有呀 可以写一个装饰器就 ok 了呀

用 pytest 吧

@user1cy(depends=["test_a"])
def test_c():
YueChen 回复

嗯啊,这个用过,感觉还是 pytest 大法好,但是当前只能用 unittets 实现😂 ,有相关思路吗

kuale 回复

有这个思路,但是写不出来,没法获取依赖方法的测试执行结果,可以给个 demo 吗 😀

写一个简单的装饰呗

import unittest


def skipTest(value):
    def deco(function):
        def wrapper(self, *args, **kwargs):
            if not getattr(self, value):
                self.skipTest('未登录跳过用例')
            else:
                function(self, *args, **kwargs)
        return wrapper
    return deco


class DemoTest(unittest.TestCase):
    isOnline = False  # 未登录

    def test_1(self):
        self.assertTrue(1 == 1)
        DemoTest.isOnline = True  # 成功登陆

    @skipTest('isOnline')
    def test_2(self):
        print("A test")


if __name__ == '__main__':
    unittest.main()
YueChen 回复

这个思路不错,但是如果有多个依赖关系的话,这样就不太好,我一直想获取 test_1 的测试结果,就是获取不到,有了 test_1 的执行结果,就可以判断了

强行去获取结果,也能获取,但是实际上,还不如楼上的用一个变量作为测试结果来的直白。

# coding=utf-8
import unittest


def skip_if_fail_register(func, depend='test_1register'):
    def decorator(self):
        fail_register = depend in [fail[0]._testMethodName for fail in self._resultForDoCleanups.failures]
        test = unittest.skipIf(fail_register, '注册失败')(func)
        return test(self)
    return decorator


class TestStringMethods(unittest.TestCase):

    def test_1register(self):
        print('注册账户')

    @user1r
    def test_2login(self):
        print('登录账户')

if __name__ == '__main__':
    unittest.main()

好啦,问题已解决,谢谢各位啦,感谢各位提出的思路,感谢@xiaoj (杰) 和@keke

在这里做个总结:

  1. xiaoj (杰) 的方法
def skipTest(value):
    def deco(function):
        def wrapper(self, *args, **kwargs):
            if not getattr(self, value):
                self.skipTest('跳过用例')
            else:
                function(self, *args, **kwargs)
        return wrapper
    return deco

这个方法适用于当前的测试类中,当且仅当只依赖一个测试用例的时候使用,比如登录,获取用户信息,退出,在这 3 个测试用例中,获取用户信息和退出都依赖登录,所以可以使用这种依赖方法,如果当前的测试用例还依赖了第二个其他的测试用例,则本方法不适应

2.keke 的方法

def dependon(depend=None):
    import functools
    def wraper_func(test_func):
        @functools.wraps(test_func)
        def inner_func(self):
            if depend == test_func.__name__:
                raise ValueError("{} cannot depend on itself".format(depend))
            print("self._resultForDoCleanups", self._resultForDoCleanups.__dict__)
            failures = str([fail[0] for fail in self._outcome.result.failures])
            errors = str([error[0] for error in self._outcome.result.errors])
            skipped = str([error[0] for error in self._outcome.result.skipped])
            flag = (depend in failures) or (depend in errors) or (depend in skipped)
            test = unittest.skipIf(flag, '{} failed  or  error or skipped'.format(depend))(test_func)
            return test(self)

        return inner_func

对这个方法做了一下小小的改动,以上就是最新的代码。其中 depend 参数的类型为 string,值就是测试用例的方法名称。

可以适用于依赖的测试用例失败或错误时都跳过测试用例,有 dependon 装饰器标记的用例必须在用例 depend(test_login)之后执行

此方法适用于 python3.4+,如果是低版本的 python3,请将 self._outcome.result 修改为 self._outcomeForDoCleanups,如果你是 python2 版本,请将 self._outcome.result 修改为 self._resultForDoCleanups

最后,再次感谢各位,祝各位春节快乐!

zhang 关闭了讨论 01月15日 16:44
ningz 近期开展的 UI 自动化项目交流下 中提及了此贴 07月04日 17:37
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册