如何在 python 中模拟 pyplot.show(以防止显示情节)
How to mock pyplot.show in python (to prevent showing plots)
我想断言 matplotlib.pyplot.show 在我的 class 方法之一中被调用,但我不希望该方法实际调用 show() 并在外部 window 在单元测试期间。无论我如何尝试模拟 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 设置 return 值。当我使用调试器时,Model class 中的 matplotlib 不会与 Mock 对象一起传播,因此我不确定如何模拟 matplotlib 模块或其成员函数。是否可以模拟 matplotlib?
关于如何在单元测试中正确模拟 matplotlib 的任何想法(主要是为了防止显示绘图)?
编辑:我可以通过将补丁装饰更改为
@patch('matplotlib.pyplot.show')
,
但我仍然不确定为什么这样做有效而我之前的尝试却没有。
当您调用 patch
时,matplotlib
模块会在内存中进行修补,因此任何 new 都会尝试访问它的子元素 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
的引用仍未被模拟。
我想断言 matplotlib.pyplot.show 在我的 class 方法之一中被调用,但我不希望该方法实际调用 show() 并在外部 window 在单元测试期间。无论我如何尝试模拟 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 设置 return 值。当我使用调试器时,Model class 中的 matplotlib 不会与 Mock 对象一起传播,因此我不确定如何模拟 matplotlib 模块或其成员函数。是否可以模拟 matplotlib?
关于如何在单元测试中正确模拟 matplotlib 的任何想法(主要是为了防止显示绘图)?
编辑:我可以通过将补丁装饰更改为
@patch('matplotlib.pyplot.show')
,
但我仍然不确定为什么这样做有效而我之前的尝试却没有。
当您调用 patch
时,matplotlib
模块会在内存中进行修补,因此任何 new 都会尝试访问它的子元素 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
的引用仍未被模拟。