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

时间:2020-07-22 10:09:37

标签: python unit-testing 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())

您能提出一种应如何正确测试这种功能的方法吗?

2 个答案:

答案 0 :(得分:1)

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

答案 1 :(得分:0)

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

PointRecorder

然后初始化上面的mock_event类。之后,定义一个适合PointRecorder.on_press方法的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() 以避免阻塞执行。

{{1}}
相关问题