星期五, 十一月 30, 2007

python 一个 unit test 代码复用实例及 **kwargs 传递

>>> def func(a, **kwargs):
... print a
... print kwargs
...
>>> def f(a, **kwargs):
... func(a, **kwargs)
...
>>> f(1, x=1)
1
{'x': 1}
注意调用的时候的方式。

在做 Python Tree 的 unit testing 的时候用到了这种方式。因为 node('update', other, ...) 即 Tree.__update__() 方法有一个 ignore_none 参数,所以在测试它的时候必须考虑到。但是否使用 ignore_none=False 的两种情况下,环境的设定是一致的,所以最好能将 ignore_onne=False 作为 **kwargs 传递给一个统一的接口:
class TestUpdate(TestTreeBase):
def doUpdate(self, other, **kwargs):
self.root('update', other, **kwargs)
这时候 doUpdate() 再调用 update 操作的时候就可以使用这种形式了。

之所以要定义一个统一的 doUpdate() 接口是因为 node += other 的形式实际上是调用了 node.__update__(),所以为了增加代码的可重用行,我当然希望 TestUpdate 和 TestIadd 能够尽可能公用代码。因为基本环节的设置都是一样的,唯一不同的是,一个是调用 self.root('update', other),而另一个是调用 self.root += other。

不过 self.root('update', other) 还可以带两个参数 self.root('update', other, ignore_none=False),但 self.root += other 只能带一个参数即 other。

为了使复用成为可能,需要在两个类中分别定义这个统一接口:
class TestUpdate(TestTreeBase):
def doUpdate(self, other, **kwargs):
self.root('update', other, **kwargs)


def _setExistedNodes(self):
self.root.new = "/new"
self.root.new.trunk = "/new/trunk"
self.root.new.trunk.branch = "/new/trunk/branch"
self.root.new.trunk['x'] = "/new/trunk(x)"
self.root.new.branch = "/new/branch"
other = Tree(None)
other.new = None
other.new.trunk = "trunk_updated"
return other

def testUpdateExistedNode(self):
# Update an existed node, both its parent and childs
# should not be affected, nor to other nodes,
# no mather its parent is root or not because the previous tests
# have prove that the root node is same as normal nodes,
temp = self.root
other = self._setExistedNodes()
self.doUpdate(other)
self.assertNodeValue(self.root, "root")
self.assertNodeValue(self.root.new, "/new")
self.assertNodeValue(self.root.new.trunk, "trunk_updated")
self.assertNodeValue(self.root.new.trunk.branch, "/new/trunk/branch")
self.assertNodeIndexValue(self.root.new.trunk, 'x', "/new/trunk(x)")
self.assertNodeValue(self.root.new.branch, "/new/branch")
self.assertPrevious("testBaseCase")
self.failUnless(self.root is temp)

def testUpdateNodeNotIgnoreNone(self):
# Don't ignore "None" setting:
temp = self.root
other = self._setExistedNodes()
self.doUpdate(other, ignore_none=False)
self.assertNodeValue(self.root, None)
self.assertNodeValue(self.root.new, None)
self.assertNodeValue(self.root.new.trunk, "trunk_updated")
self.assertNodeValue(self.root.new.trunk.branch, "/new/trunk/branch")
self.assertNodeIndexValue(self.root.new.trunk, 'x', "/new/trunk(x)")
self.assertNodeValue(self.root.new.branch, "/new/branch")
self.assertPrevious("testBaseCase")
self.failUnless(self.root is temp)
......

class TestIadd(TestUpdate):
def doUpdate(self, other, **kwargs):
self.root += other


def testUpdateNodeNotIgnoreNone(self):
pass

def testUpdateIndexNotIgnoreNone(self):
pass

def testIaddTreeDictForNew(self):
temp = self.root
self.root += {
('new',) : Tree("/new"),
('new', ('x',)) : Tree("/new(x)"),
('new1', ('x', 'y')) : Tree("/new1(x)(y)"),
('new', 'branch', 'data') : Tree(['new', 'branch', 'data'])
}
self.assertNodeValue(self.root.new, "/new")
self.assertNodeIndexValue(self.root.new, 'x', "/new(x)")
self.assertNodeValue(self.root.new1, None)
self.assertNodeIndexValue(self.root.new1, 'x', None)
self.assertNodeIndexValue(self.root.new1['x'], 'y', "/new1(x)(y)")
self.assertNodeValue(self.root.new.branch, None)
self.assertNodeValue(self.root.new.branch.data, ['new', 'branch', 'data'])
self.assertPrevious("testBaseCase")
self.failUnless(self.root is temp)
......
注意两个类中 doUpdate() 接口的定义。对 TestIadd 来说,因为不存在 ignore_none 参数的问题,所以就让 testUpdateNodeNotIgnoreNone 和 testUpdateIndexNotIgnoreNone 直接通过好了。

__package__ = "caxes"
__revision__ = 263

没有评论: