簡體   English   中英

如何對設置內部數據但不返回的方法進行單元測試?

[英]How do I unit test a method that sets internal data, but doesn't return?

根據我的閱讀,單元測試應該一次只測試一個函數/方法。 但是我不清楚如何測試只設置沒有返回值的內部對象數據來測試的方法,就像下面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]

如果單元測試法規定我們應該一次測試一個函數,那么如何自己測試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

幫助贊賞

誤解

你在這里遇到的真正問題是你正在做一個錯誤的前提:

如果單元測試法規定我們應該測試每個功能,一次一個...

這根本不是什么好的單元測試。

良好的單元測試是將代碼分解為邏輯組件,將它們置於受控環境中,並從消費者的角度測試其實際行為是否符合其預期行為。

那些“單位”可能(取決於你的環境)匿名函數,單個類或緊耦合類的集群(並且不要讓任何人告訴你類耦合本質上是壞的;有些類是一起進行的)。

問自己重要的是 - 消費者關心什么

他們當然關心的是 - 當他們調用set方法時 - 設置一些他們甚至無法訪問的內部私有成員。

解決方案

天真地,通過查看你的代碼,似乎消費者關心的是當他們為特定鍵調用setvalue為同一個鍵調用getvalue他們返回他們放入的值。如果這是他們的預期行為單位(類),那就是你應該測試的東西。

只要行為正確,沒有人應該關心幕后發生的事情。

但是,我還會考慮是否真的是這個課程的所有內容 - 這個價值還有什么影響呢? 從你的問題中的例子中說出來是不可能的,不管它是什么,都應該進行測試。

或許,如果這很難定義,這個類本身並不是很有意義,你的“單元”實際上應該是一個獨立的小類集合,當它們放在一起時才真正具有有意義的行為,並且應該如此測試。

然而,這里的平衡是微妙的,如果沒有更多的背景,很難不那么神秘。

陷阱

你當然不應該 (從來沒有)做的是讓你的測試探索對象的內部狀態。 這有兩個非常重要的原因:

首先,如前所述,單元測試是關於客戶所感知的單元行為。 測試它做了我認為它應該作為消費者做的事情。 我不 - 也不應該 - 關心它是如何做到的。 那本字典對我來說無關緊要。

其次,良好的單元測試允許您驗證行為,同時仍然可以自由地改變行為的實現方式 - 如果將測試與該字典綁定,它將不再是實現細節並成為合同的一部分,這意味着任何更改如何實施此單元會強制您保留該字典或更改測試。

這條道路與單元測試的目的相反 - 無痛維護。

最重要的是,消費者 - 以及您的測試 - 並不關心setvalue是否更新內部字典。 弄清楚他們真正關心的是什么並測試它。

順便說一下,這就是TDD(特別是測試優先)真正發揮作用的地方 - 如果你預先通過測試表明預期的行為,很難發現自己陷入了“我想測試什么?” 發情。

我會考慮在你的測試中訪問你的內部數據結構而不是“惡心的黑客”,因為它一次測試一個函數,你幾乎立即知道什么是錯的。

我承認從測試中訪問私有成員並不是一個好主意,但我仍然看到這增加了更多價值:

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]


def test_alpha_setvalue():
    alpha = Alpha()
    alpha.setvalue('abc', 33)
    assert alpha._internal_dict['abc'] == 33


def test_alpha_getvalue():
    alpha = Alpha()
    alpha._internal_dict['abc'] = 33
    assert alpha.getvalue('abc') == 33

請注意,此方法要求您為內部數據結構使用單個下划線,以便測試能夠訪問它。 遵循的慣例是向其他程序員表明它是非公開的。

有關python docs的更多信息: https//docs.python.org/3/tutorial/classes.html#tut-private

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM