如何对设置内部数据但不返回的方法进行单元测试?

Pau*_*l W 8 python unit-testing

根据我的阅读,单元测试应该一次只测试一个函数/方法.但是我不清楚如何测试只设置没有返回值的内部对象数据来测试的方法,就像下面Python类中的setvalue()方法一样(这是一个更复杂的简单表示):

class Alpha(object):

    def __init__(self):
        self.__internal_dict = {}

    def setvalue(self, key, val):
        self.__internal_dict[key] = val

    def getvalue(self, key):
        return self.__internal_dict[key]
Run Code Online (Sandbox Code Playgroud)

如果单元测试法规定我们应该一次测试一个函数,那么如何自己测试setvalue()方法呢?一个"解决方案"是将我传入setvalue()的内容与getvalue()的返回进行比较,但如果我的断言失败,我不知道哪个方法失败 - 是setvalue()还是getvalue()?另一个想法是将我传入setvalue()的内容与对象的私有数据__internal_dict [key]进行比较 - 一个巨大的恶心黑客!

截至目前,这是我对这类问题的解决方案,但如果断言提出,那只会表明我的两个主要方法中有一个没有正常工作.

import pytest

def test_alpha01():
    alpha = Alpha()
    alpha.setvalue('abc', 33)

    expected_val = 33
    result_val = alpha.getvalue('abc')

    assert result_val == expected_val
Run Code Online (Sandbox Code Playgroud)

帮助赞赏

Ant*_*t P 9

误解

你在这里遇到的真正问题是你正在做一个错误的前提:

如果单元测试法规定我们应该测试每个功能,一次一个...

这根本不是什么好的单元测试.

良好的单元测试是将代码分解为逻辑组件,将它们置于受控环境中,并从消费者的角度测试其实际行为是否符合其预期行为.

那些"单位"可能(取决于你的环境)匿名函数,单个类或紧耦合类的集群(并且不要让任何人告诉你类耦合本质上是坏的;有些类是一起进行的).

问自己重要的是 - 消费者关心什么

他们当然关心的是 - 当他们调用set方法时 - 设置一些他们甚至无法访问的内部私有成员.

解决方案

天真地,通过查看你的代码,似乎消费者关心的是,当他们调用setvalue特定的密钥时,调用getvalue相同的密钥会让他们回到他们输入的值.如果这是单元的预期行为( (那)那就是你应该测试的东西.

只要行为正确,没有人应该关心幕后发生的事情.

但是,我还会考虑是否真的是这个课程的所有内容 - 这个价值还有什么影响呢?从你的问题中的例子中说出来是不可能的,不管它是什么,都应该进行测试.

或许,如果这很难定义,这个类本身并不是很有意义,你的"单元"实际上应该是一个独立的小类集合,当它们组合在一起时才真正具有有意义的行为,并且应该如此测试.

然而,这里的平衡是微妙的,如果没有更多的背景,很难不那么神秘.

陷阱

你当然不应该(从来没有)做的是让你的测试探索对象的内部状态.这有两个非常重要的原因:

首先,如前所述,单元测试是关于客户所感知的单元行为.测试它做了我认为它应该作为消费者做的事情.我不 - 也不应该 - 关心它是如何做到的.那本字典对我来说无关紧要.

其次,良好的单元测试允许您验证行为,同时仍然可以自由地改变行为的实现方式 - 如果将测试与该字典绑定,它将不再是实现细节并成为合同的一部分,这意味着任何更改如何实施此单元会强制您保留该字典或更改测试.

这条道路与单元测试的目的相反 - 无痛维护.

最重要的是,消费者 - 以及您的测试 - 并不关心是否setvalue更新内部字典.弄清楚他们真正关心的是什么并测试它.

顺便说一下,这就是TDD(特别是测试优先)真正发挥作用的地方 - 如果你预先通过测试表明预期的行为,很难发现自己陷入了"我想测试什么?" 发情.