web-dev-qa-db-ja.com

matplotlibを使用するコードに対してユニットテストを作成するにはどうすればよいですか?

私は多くの異なるmatplotlib図を生成するpython(2.7)プログラムに取り組んでいます(データはランダムではありません)。(unittestを使用して)いくつかのテストを実装するつもりです。生成された図が正しいことを確認します。たとえば、期待される図(データまたは画像)をどこかに保存し、関数を実行して結果を参照と比較します。これを行う方法はありますか?

35
pierre bonneel

私の experience では、画像比較テストは、価値があるよりも多くの問題を引き起こすことになります。これは、フォントや使用可能な描画バックエンドがわずかに異なる可能性のある複数のシステム(TravisCIなど)間で継続的インテグレーションを実行する場合に特に当てはまります。関数が完全に正しく機能している場合でも、テストに合格し続けるのは大変な作業になる可能性があります。さらに、この方法でテストするには、gitリポジトリに画像を保持する必要があります。これにより、コードを頻繁に変更する場合、リポジトリがすぐに肥大化する可能性があります。

私の意見では、(1)matplotlibが実際に図を正しく描画すると想定し、(2)プロット関数によって返されたデータに対して数値テストを実行することをお勧めします。 (どこを見ればよいかわかっている場合は、このデータをAxesオブジェクト内でいつでも見つけることができます。)

たとえば、次のような単純な関数をテストするとします。

import numpy as np
import matplotlib.pyplot as plt
def plot_square(x, y):
    y_squared = np.square(y)
    return plt.plot(x, y_squared)

ユニットテストは次のようになります

def test_plot_square1():
    x, y = [0, 1, 2], [0, 1, 2]
    line, = plot_square(x, y)
    x_plot, y_plot = line.get_xydata().T
    np.testing.assert_array_equal(y_plot, np.square(y))

または、同等に、

def test_plot_square2():
    f, ax = plt.subplots()
    x, y = [0, 1, 2], [0, 1, 2]
    plot_square(x, y)
    x_plot, y_plot = ax.lines[0].get_xydata().T
    np.testing.assert_array_equal(y_plot, np.square(y))
34
mwaskom

Matplotlibには テストインフラストラクチャ があります。例えば:

import numpy as np
import matplotlib
from matplotlib.testing.decorators import image_comparison
import matplotlib.pyplot as plt

@image_comparison(baseline_images=['spines_axes_positions'])
def test_spines_axes_positions():
    # SF bug 2852168
    fig = plt.figure()
    x = np.linspace(0,2*np.pi,100)
    y = 2*np.sin(x)
    ax = fig.add_subplot(1,1,1)
    ax.set_title('centered spines')
    ax.plot(x,y)
    ax.spines['right'].set_position(('axes',0.1))
    ax.yaxis.set_ticks_position('right')
    ax.spines['top'].set_position(('axes',0.25))
    ax.xaxis.set_ticks_position('top')
    ax.spines['left'].set_color('none')
    ax.spines['bottom'].set_color('none')

docs から:

このテストを初めて実行するときは、比較するベースラインイメージがないため、テストは失敗します。出力画像(この場合はresult_images/test_category/spines_axes_positions。*)をソースディレクトリ(この場合はlib/matplotlib/tests/baseline_images/test_category)のbaseline_imagesツリーの正しいサブディレクトリにコピーします。テストを再実行すると、合格するはずです。

13
elyase