如何在Python中模拟pyplot.show(以防止显示图表)

6

我想确认在我的类方法中是否调用了matplotlib.pyplot.show方法,但是我不希望该方法在单元测试期间实际调用show()并在外部窗口上绘制图形。无论我如何尝试mock matplotlib,它似乎都不起作用。我将列出代码的重要部分:

#In Model Test Class:
import Model
import matplotlib
import unittest
from unittest.mock import patch

class Model_Test(unittest.TestCase):

    @patch('matplotlib.pyplot')
    def test_plot_data(self, mock_pyplot):
        model = Model()
        model.plot_data()
        mock_pyplot.show.assert_called_once()

#In Model Class:
import matplotlib.pyplot as plt
import pandas as pd

class Model(object):
    ... # (__init__ and other methods)
    def plot_data(self):
        self.dataframe.plot(y=self.dataframe.columns, subplots=False, figsize=(15, 8), fontsize=12)
        plt.title('Data for Model Version: ' + self.version, fontsize=20)
        plt.xlabel('timestamp', fontsize=12)
        plt.ylabel('value', fontsize=12)
        plt.show()

我还尝试为mock_plot.show设置返回值。当我使用调试器时,Model类中的matplotlib未传播Mock对象,因此我不确定如何mock matplotlib模块或其成员函数。是否可以mock matplotlib?
有任何想法如何在单元测试中正确地mock matplotlib(主要是防止显示图形)?
编辑:我通过将修补程序装饰更改为@patch('matplotlib.pyplot.show')使其正常工作,但我仍然不确定为什么之前的尝试失败。
1个回答

7
当你调用patch时,matplotlib模块会被修改内存,所以任何新的尝试访问它的子元素pyplot都将引用模拟对象。然而,包含Model的模块已经直接引用了matplotlib.pyplot;在导入时它获取了这个引用。它不会再次通过修改后的matplotlib模块来查找。当你直接修改show时,patch将改变共享的pyplot模块。我们可以通过在模块加载时获得原始show函数的直接引用来说明这一点。
# bla.py
#import numpy as np
import matplotlib.pyplot as plt

show = plt.show

class A:
    def __init__(self):
        print(type(plt))
        print(type(plt.show))
        print(type(show))

Python控制台:

>>> from unittest.mock import patch
>>> from bla import A
>>> with patch('matplotlib.pyplot') as p:
...   A()
... 
<class 'module'>
<class 'function'>
<class 'function'>
<bla.A object at 0x7f232b98a400>
>>> with patch('matplotlib.pyplot.show') as p:
...   A()
... 
<class 'module'>
<class 'unittest.mock.MagicMock'>
<class 'function'>
<bla.A object at 0x7f232b98d550>

您会注意到,在bla模块中获得的对show的引用仍未被模拟。

这是关于Python中一般模拟的极其有用的信息。我之前没有考虑到未模拟引用是在导入时建立的,而在打补丁之前。谢谢! - glaceonix

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