使用Unittest模拟pandas的to_csv函数

7

mymodule.py

def write_df_to_csv(self, df, modified_fn):
    new_csv = self.path + "/" + modified_fn
    df.to_csv(new_csv, sep=";", encoding='utf-8', index=False)

test_mymodule.py

class TestMyModule(unittest.TestCase):
    def setUp(self):
        args = parse_args(["-f", "test1"])
        self.mm = MyModule(args)
        self.mm.path = "Random/path"

    self.test_df = pd.DataFrame(
                [
                    ["bob", "a"],
                    ["sue", "b"],
                    ["sue", "c"],
                    ["joe", "c"],
                    ["bill", "d"],
                    ["max", "b"],
                ],
                columns=["A", "B"],
            )

def test_write_df_to_csv(self):
    to_csv_mock = mock.MagicMock()
    with mock.patch("project.mymodule.to_csv", to_csv_mock, create=True):
        self.mm.write_df_to_csv(self.test_df, "Stuff.csv")
    to_csv_mock.assert_called_with(self.mm.path + "/" + "Stuff.csv")

当我运行这个测试时,我会得到:
FileNotFoundError: [Errno 2] No such file or directory: 'Random/path/Stuff.csv'

我正在尝试在我的方法中模拟to_csv。我的其他测试按预期运行,但是我不确定我在这个测试中做错了什么。我的使用魔法模拟是正确的吗,还是我忽略了其他东西?


1
project.mymodule.to_csv和Pandas的DataFrameto_csv方法不是同一个吧? - Thomas
@Thomas,我相信这与df.to_csv中的df部分有关。 - pymat
3个回答

5

另一种方法是

import unittest.mock as mock
import unittest
import pandas as pd

import project.mymodule as mm

class TestMyModule(unittest.TestCase):

    def test_write_df_to_csv(self):
        test_df = pd.DataFrame(...)
        with mock.patch("pandas.DataFrame.to_csv") as to_csv_mock:
            mm.write_df_to_csv(test_df, "Stuff.csv")
            to_csv_mock.assert_called_with("Stuff.csv")

if __name__ == '__main__':
    unittest.main()'''

这并没有真正回答问题。如果您有不同的问题,可以通过点击提问来提出。如果您想在此问题获得新的答案时得到通知,您可以关注此问题。一旦您拥有足够的声望,您还可以添加悬赏以吸引更多关注。- 来自审核 - rv.kvetch
@rv.kvetch 抱歉,但这是对问题的确切回答。然而,我不知道它是否有效。 - Ali Berat Çetin

3

您没有提供一个最小的、可重现的示例,所以我不得不删除一些内容使其正常工作。我想你可以自己填补缺失的部分。

一个问题是 mock.patch("project.mymodule.to_csv", ...),它试图模拟一个叫做 to_csv 的类在 import 路径为 project.mymodule 的模块中。这只有在你传递了 create=True 的情况下才“有效”,但当然模拟一个之前不存在的东西是没有效果的,因为没有人会调用它。

您可以使用 mock.patch("pandas.DataFrame", ...) 来 mock 整个 DataFrame 类。注意:无论您当前模块如何(甚至是否)导入了 pandas,都不是 pd

但是这样一来,您的单元测试将断言在 任何 DataFrame 上调用了 to_csv,而不仅仅是您传递的那个。通过仅在我们传递给 write_df_to_csv 的一个 DataFrame 对象上模拟 to_csv 方法,测试变得更加全面,并且更容易理解。我们可以使用 mock.patch.object 来实现这一点。

mock.patch.object 返回模拟函数,我们可以随后调用断言。因为它是一个方法模拟,而不是一个自由函数,所以在断言中我们不需要传递 self 参数。

project/mymodule.py

def write_df_to_csv(df, file_name):
    df.to_csv(file_name, sep=";", encoding='utf-8', index=False)

project/test_mymodule.py

import unittest.mock as mock
import unittest

import pandas as pd

import project.mymodule as mm

class TestMyModule(unittest.TestCase):

    def test_write_df_to_csv(self):
        test_df = pd.DataFrame(...)
        with mock.patch.object(test_df, "to_csv") as to_csv_mock:
            mm.write_df_to_csv(test_df, "Stuff.csv")
            to_csv_mock.assert_called_with("Stuff.csv")

if __name__ == '__main__':
    unittest.main()

输出

现在测试会以合适的方式失败,因为实际上参数并不匹配!

$ python -m project.test_mymodule
F
======================================================================
FAIL: test_write_df_to_csv (__main__.TestMyModule)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/tmp/project/test_mymodule.py", line 25, in test_write_df_to_csv
    to_csv_mock.assert_called_with("Stuff.csv")
  File "/usr/lib/python3.8/unittest/mock.py", line 913, in assert_called_with
    raise AssertionError(_error_message()) from cause
AssertionError: expected call not found.
Expected: to_csv('Stuff.csv')
Actual: to_csv('Stuff.csv', sep=';', encoding='utf-8', index=False)

----------------------------------------------------------------------
Ran 1 test in 0.003s

FAILED (failures=1)

谢谢您。实际上,我修改了最后一行代码: to_csv_mock.assert_called_with(self.mm.path + "/" + "Stuff.csv", sep=";", encoding='utf-8', index=False) - pymat

0

你必须以正斜杠开头。这是已更正的代码:

self.mm.path = "/Random/path/"

同时更改:

to_csv_mock.assert_called_with(self.mm.path + "Stuff.csv")

编辑:正如@Thomas所说,我不确定project.mymodule.to_csv是否正确!


我已经修改了,但是错误信息仍然相同。 - pymat
好的,我得查一下 Mac 路径的格式如何。 - DapperDuck

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接