如何对方法对象中的方法进行单元测试?
我进行了一个叫做“用方法对象替换方法”的重构,这个方法是由Beck描述的。
现在,我有一个类里面有一个“run()”方法,还有一些成员函数,这些函数把计算过程拆分成更小的部分。我该如何测试这些成员函数呢?
我最初的想法是,我的单元测试基本上就是“run()”方法的复制(只是初始化不同),但是在每次调用成员函数之间加上断言,以检查计算的状态。
(我在使用Python和unittest模块。)
class Train:
def __init__(self, options, points):
self._options = options
self._points = points
# other initializations
def run(self):
self._setup_mappings_dict()
self._setup_train_and_estimation_sets()
if self._options.estimate_method == 'per_class':
self._setup_priors()
self._estimate_all_mappings()
self._save_mappings()
def _estimate_all_mappings():
# implementation, calls to methods in this class
#other method definitions
我对成员属性在调用不同方法前后的状态有一定的期望,这些都是“run()”方法实现的一部分。我应该对这些“私有”属性进行断言吗?我不知道还有什么其他方法可以对这些方法进行单元测试。
另外一个选择是,我其实根本不应该测试这些。
3 个回答
这里有两个原则需要注意。第一个原则是,公共方法应该是你想要对外提供的公共接口。在这个例子中,公开 run()
方法是合适的,而公开 estimate_all_mappings()
方法就不合适,因为你不希望其他人随便调用这个函数。
第二个原则是,一个函数应该只做一件事情。在这个例子中,run()
方法负责整合多个复杂操作的结果。而 estimate_all_mappings()
方法则是执行其中一个复杂操作。它可能还会调用另一个函数 estimate_map()
,这个函数只负责进行一次单独的估算,然后 estimate_all_mappings()
会把这些结果汇总起来。
因此,进行这种责任的分配是正确的。接下来只需要知道如何 测试一个私有方法。
另外,创建另一个类的唯一理由是,如果有某些功能的子集可以组成一个独立的行为单元。比如说,你不会创建一个类 B,它只会被类 A 调用或使用,除非有某种状态更容易作为对象传递。
我喜欢你的回答,但我有不同的看法。
使用这种设计模式的情况通常是当操作比较复杂的时候。因此,能够检查这个操作中每个部分的情况,我觉得是非常重要的。
接下来,你可能会遇到依赖其他资源的问题(在这个情况下可能存在,也可能不存在)。
你需要使用某种控制反转的方法,这样才能插入一个模拟对象,以便把这个类隔离开来。
而且大多数模拟框架都会提供一些方法,让你可以访问私有成员。
我来回答我自己的问题。经过一番阅读和思考,我觉得我不应该对这些私有方法进行单元测试。我应该只测试公共接口。如果那些负责内部处理的私有方法足够重要,值得单独测试,而不仅仅是当前实现的巧合,那么这可能意味着它们应该被重构到一个单独的类中。