如何为交互式matplotlib图形编写单元测试



我想为交互式matplotlib绘图编写unittest。我的问题是,我找不到模拟按键或鼠标按键事件的好方法。我知道pyautogui,但我必须关心matplotlib窗口在屏幕上的位置(例如,在TravisCI上,如果不配置它,我怀疑它是否能正常工作(。我试过查看Matplotlib的单元测试,但还找不到任何有用的东西。最好的解决方案是在不涉及GUI部分的情况下在代码中触发事件,但到目前为止我无法解决它

我想出的最简单的例子如下。可以使用i键在绘图上标记点。这里我要测试的函数是on_press

import numpy as np
import matplotlib.pyplot as plt
class PointRecorder:
    def __init__(self, x, y):
        plt.ion()
        self.figure = plt.figure()
        self.cid = self.figure.canvas.mpl_connect("key_press_event", self.on_press)
        self.x = x
        self.y = y
        self.x_points, self.y_points = [2], [0.5]
        plt.plot(self.x, self.y, "r")
        self.pts, = plt.plot(self.x_points, self.y_points, "ko", markersize=6, zorder=99)
        plt.show(block=True)
    def on_press(self, event):
        ix, iy = event.xdata, event.ydata
        if event.inaxes is None:
            return
        if event.key == 'i':
            self.x_points.append(ix)
            self.y_points.append(iy)
            self.pts.set_data(self.x_points, self.y_points)
        if self.pts.stale:
            self.figure.canvas.draw_idle()

    def get_data(self):
        return self.pts.get_data()
if __name__ == "__main__":
    x = np.linspace(0, 6, 100)
    y = np.sin(x)
    graph = PointRecorder(x, y)
    print(*graph.get_data())

你能建议如何正确测试这种功能吗?

我不是单元测试专家,但我的猜测是,您需要实例化一个Event对象(在key_press_Event的情况下,它应该是一个KeyEvent(,并从测试代码中调用graph.on_press(event)

根据建议,解决方案如下:首先定义一个空白事件。

from unittest import mock
def mock_event(xdata, ydata, button, key, fig, canvas, inaxes=True):
    event = mock.Mock()
    event.button = button
    event.key = key
    event.xdata, event.ydata = xdata, ydata
    event.inaxes = inaxes
    event.fig = fig
    event.canvas = canvas
    event.guiEvent = None
    event.name = 'MockEvent'
    return event

然后初始化上面的PointRecorder类。然后,定义一个适合PointRecorder.on_press方法的mock_event。还有patch plt.show,以避免阻塞执行。

@mock.patch("matplotlib.pyplot.show")
def test_insert(mock_show):
    x, y = np.arange(100), np.arange(100)
    
    obj = PointRecorder(x, y)
    mck = mock_event(xdata=50, ydata=40, button="i", key="i", fig=obj.figure, canvas=obj.figure.canvas, inaxes=True)
    obj.on_clicked(event=mck)
    a, b = obj.get_data()
    np.testing.assert_array_equal(a, np.array([2, 50])) # 2 was originally in the __init__
    np.testing.assert_array_equal(b, np.array([0.5, 40])) # 0.5 was originally in the __init__
    mock_show.assert_called()

相关内容

  • 没有找到相关文章

最新更新