unittest和metaclass:自动生成test_ *方法 [英] unittest and metaclass: automatic test_* method generation

查看:40
本文介绍了unittest和metaclass:自动生成test_ *方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在为框架创建测试时,我开始注意到以下模式:

As I create tests for a framework, I start noticing the following pattern:

class SomeTestCase(unittest.TestCase):

    def test_feat_true(self):
        _test_feat(self, True)

    def test_feat_false(self):
        _test_feat(self, False)

    def _test_feat(self, arg):
        pass    # test logic goes here

所以我想以编程方式为带有元类的这些类型的测试类创建test_feat_*方法.换句话说,对于每个带有签名_test_{featname}(self, arg)的私有方法,我希望创建两个带有签名test_{featname}_true(self)test_{featname}_false(self)的顶级可发现方法.

So I want to programmatically create test_feat_* methods for these type of test classes with a metaclass. In other words, for each private method with signature _test_{featname}(self, arg), I want two top-level, discoverable methods with the signatures test_{featname}_true(self) and test_{featname}_false(self) to be created.

我想出了类似的东西:

#!/usr/bin/env python

import unittest


class TestMaker(type):

    def __new__(cls, name, bases, attrs):
        callables = dict([
            (meth_name, meth) for (meth_name, meth) in attrs.items() if
            meth_name.startswith('_test')
        ])

        for meth_name, meth in callables.items():
            assert callable(meth)
            _, _, testname = meth_name.partition('_test')

            # inject methods: test{testname}_{[false,true]}(self)
            for suffix, arg in (('false', False), ('true', True)):
                testable_name = 'test{0}{1}'.format(testname, suffix)
                attrs[testable_name] = lambda self: meth(self, arg)

        return type.__new__(cls, name, bases, attrs)


class TestCase(unittest.TestCase):

    __metaclass__ = TestMaker

    def _test_this(self, arg):
        print 'this: ' + str(arg)

    def _test_that(self, arg):
        print 'that: ' + str(arg)


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

我期望一些输出,例如:

I expect some output like:

this: False
this: True
that: False
that: True

但是我得到的是:

$ ./test_meta.py
that: True
.that: True
.that: True
.that: True
.
----------------------------------------------------------------------
Ran 4 tests in 0.000s

OK

似乎我缺少一些关闭规则.我该如何解决?有更好的方法吗?

It looks like there are some closure rules that I am missing. How do I get around this? Is there a better approach?

谢谢

edit :已修复.参见:摘录.

推荐答案

实际上,这是一个关闭问题:

Indeed, it is a closure issue:

更改

attrs[testable_name] = lambda self: meth(self, arg)

attrs[testable_name] = lambda self,meth=meth,arg=arg: meth(self, arg)

通过使用默认值,lambda内部的arg绑定到在每次循环迭代期间设置的默认值arg.如果没有默认值,在循环的所有迭代完成后,arg将采用最后的值arg. (meth也是如此).

By using a default value, arg inside the lambda is bound to the default value arg set during each iteration of the loop. Without the default value, arg takes on the last value of arg after all the iterations of the loop have completed. (And the same goes for meth).

这篇关于unittest和metaclass:自动生成test_ *方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆