如何构建Python模块以使其既可扩展又可测试?

时间:2014-06-22 10:20:34

标签: python unit-testing module structure

我正在编写一些Python模块,用于我自己的处理加密货币的应用程序。许多函数根据给定的字符串返回一些东西:

def doStuff(coin, value):
    if coin == 'BTC':
        return doSomethingWithBTC(value, 'some_string')
    elif coin == 'LTC':
        return someModule.doLTC(value, 1)
    elif coin == 'DOGE':
        return otherMod.DOGE(value, 52, True)
    else:
        return 'Some terrible error occurred.'

如您所见,密钥是一组预定义的字符串(加密货币)之一。目前该集合中有三个,但我希望将来扩展这个数字。我在这个模块中还有十几个函数,目前它们都使用相同的三个字符串,但是当我添加一个函数时,所有函数都需要扩展。

我已经为这个模块进行了单元测试,现在我想测试所有函数是否能够将集合中的所有(当前3个)项目作为键。我可以通过调用它们来做到这一点,但是其中一些做了我在单元测试中无法真正测试的东西。其中一个以(比特币)付款为例。

我现在想到使用inspect模块获取函数的源代码,看它是否包含一行包含key == 'X',其中X是预定义集合中的每个项目。虽然我猜这会起作用,但对我来说听起来并不是Pythonic。

有没有人知道如何制作这些功能,以便我可以测试他们是否能够处理预定义集合中的所有货币而不实际调用这些函数?欢迎所有提示!

2 个答案:

答案 0 :(得分:2)

使用if-cascades也不是非常pythonic。如果每个键有很多方法,只需使用类并通过字典访问它们:

class BTC(object):
    def do_stuff(self, value):
        return doSomethingWithBTC(value, 'some_string')

class LTC(object):
    ...

CURRENCIE_INSTANCES = {
    'BTC': BTC(),
    'LTC': LTC(),
}

def do_stuff(key, value):
    return CURRENCIE_INSTANCES[key].do_stuff(value)

这样,你不必改变你的东西 - 方法,只需要改变一个字典。

答案 1 :(得分:0)

这种方法怎么样:

from functools import partial

def doStuff(key, value):

    method_btc = partial(doSomethingWithBTC, kw2='some_string')
    method_ltc = partial(someModule.doLTC, kw2=1)
    method_doge = pattial(otherMod.DOGE, kw2=52, kw3=True)
    dct = dict(BTC=method_btc, LTC=method_ltc, DOGE=method_doge)

    if key in dct:
        return dct.get(key)(value)
    else:
        return 'Some terrible error occurred.'

您始终可以使用新密钥和方法扩展字典 dct