Python 单元测试模拟。ValueError:DataFrame 的真值不明确

Har*_*ary 7 python pandas python-unittest python-unittest.mock

我正在为我的 python 2.7 方法之一编写单元测试用例。

在我的测试方法中,有一个方法调用将带有字符串键和 panadas 数据框的字典作为该键的值。

我想为此方法编写一个交互测试,以检查它是否使用正确的字典在内部调用该方法

def MethodUnderTest(self):
    #some code here
    externalMethod(dictionary_of_string_dataframe)
    #some code here
Run Code Online (Sandbox Code Playgroud)

在单元测试中,我确实编写了我的断言来测试这种交互

mock_externalClass.externalMethod.assert_called_once_with(dictionary_of_string_dataframe) 
Run Code Online (Sandbox Code Playgroud)

我创建 dictionary_of_string_dataframe 的方式与在实际方法中创建的方式完全相同。事实上,我复制了在测试代码中执行此操作的辅助方法只是为了确保两个字典相同。我什至在 python 控制台上调试测试方法时打印了两个字典,两者看起来完全一样。

我使用 @patch 装饰器修补外部类,一切正常。

问题是在上面提到的 assert 语句中,我收到以下错误:

 mock_externalClass.externalMethod.assert_called_once_with(dictionary_of_string_dataframe)
  File "C:\Python27\lib\site-packages\mock\mock.py", line 948, in assert_called_once_with
    return self.assert_called_with(*args, **kwargs)
  File "C:\Python27\lib\site-packages\mock\mock.py", line 935, in assert_called_with
    if expected != actual:
  File "C:\Python27\lib\site-packages\mock\mock.py", line 2200, in __ne__
    return not self.__eq__(other)
  File "C:\Python27\lib\site-packages\mock\mock.py", line 2196, in __eq__
    return (other_args, other_kwargs) == (self_args, self_kwargs)
  File "C:\Python27\lib\site-packages\pandas\core\generic.py", line 953, in __nonzero__
    .format(self.__class__.__name__))
ValueError: The truth value of a DataFrame is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
Run Code Online (Sandbox Code Playgroud)

我确实搜索了 valueError 但没有太大帮助。有人能告诉我这里发生了什么吗?

我确实检查了以下问题,但这没有帮助

ValueError:DataFrame 的真值不明确。使用 a.empty、a.bool()、a.item()、a.any() 或 a.all()

sfo*_*gle 7

我在尝试测试我编写的函数是否被某个预处理数据帧调用时也遇到了这个问题,我使用mock's call_args 属性和pandas's解决了这个问题testing.assert_frame_equal

在我的情况下,我想断言作为第二个参数传递给下面score_function调用的由更高级别函数调用的函数的数据帧的值run_scoring。因此,首先我使用 检索了*args对模拟的方法调用的一部分,[0]然后使用[1].

然后我可以使用pd.testing.assert_frame_equal.

from unittest.mock import Mock
import pandas as pd

import my_code

...

score_function_mocked = Mock()
my_code.score_function = score_function_mocked
my_code.run_scoring()

pd.testing.assert_frame_equal(
    # [0] = *args, [0][1] = second positional arg to my function
    score_function_mocked.call_args[0][1],
    pd.DataFrame({
        'new_york': [1, 0],
        'chicago': [0, 1],
        'austin': [0, 0]
    })

)
Run Code Online (Sandbox Code Playgroud)


eri*_*man 5

我通过使用 SAME_DF 类解决了这个问题,类似于模拟的 ANY 类

class SAME_DF:
    def __init__(self, df: pd.DataFrame):
        self.df = df

    def __eq__(self, other):
        return isinstance(other, pd.DataFrame) and other.equals(self.df)
 
def test_called_with_df():
    ....
    mock.method.assert_called_once_with(SAME_DF(pd.DataFrame({
        'name': ['Eric', 'Yoav'],
        'age': [28, 34]
    })))
Run Code Online (Sandbox Code Playgroud)


vic*_*tor 4

==发生这种情况是因为 unittest.mock 使用或 来比较输入值!=。但是,pandas dataframes 不能进行类似的比较,必须使用.equalsDataFrames 的方法。

https://github.com/testing-cabal/mock/blob/master/mock/mock.py

一种可能的解决方法是编写自己的单元测试,该测试迭代字典并使用该.equals方法在数据帧之间进行比较。

另一种方法是重写__equals__pandas 数据帧的方法,以便在mock它们之间进行比较时它将使用正确的方法。