ハリボテ(モックアップ)で動かして確認できる安心感を得ましょう

ハリボテ(モックアップ) プログラミング

#プログラミング #モックアップ #安心 #テストできない #動かせない #k-means法

本記事中のプログラム例を示すところでは、主としてpythonで記述します。
pythonは現在人気の言語であるということも理由ですが、小生は他の言語との類似性やAIなどにも活用できるという長所など、総合的に他の言語に比べてpythonを推奨しているためです。
また、Windows上でShift-JISコードで利用することを前提にしています。
スポンサーリンク

テストしたくてもできない!

プログラミングにおいては、時として、動作させて確認することができない場面に遭遇することがあります。
例えば、以下のようなケースです。

・ 共同でプログラミングしていて他の人のプログラムができる前にテストしたい
・ 未入手のシステムやソフトウェアの一部を作っていてテストをしたい

このようなケースで、自分のプログラミングが先行し、他者が遅れてしまっている場合を考えます。
こういった場合、その後、プログラム同士を結合して結合テスト(*1)を行いますが、そのときに初めて動作させることになります。
この時、たいていプログラムのインターフェース(*2)が合っていないことが判明して、ただでさえ納期が短くなっている中、炎上することになります。
小生は過去に作り直しをするはめになったことがありました。。。

*1 結合テストとは、複数の担当が作成したプログラムを持ち寄って結合させて1つの完成品を作成して行なうテストのことです。
そのため、結合テストのときになって初めて、プログラムだけでなく、担当が各々で考えていたことが周りと合っているかが試されます。
ですので、よほどのことがない限り、一発で成功するということはありません。
*2 インタフェースとは、プログラム同士の接合部分にある関数やメソッドの、例えば以下のような要素のことを指します。

– 引数、返り値
– エラー、例外
– データの構造(リスト、ディクショナリ、レコードなど)

プログラムを作る前から、担当者同士でどのようなインターフェースにするかを決める必要があるため、通常はインターフェース仕様書と呼ぶ仕様書を作成して担当者同士で合意して進めます。

どうやって進めるか

まだ存在しない部分を、モックアップ(ハリボテプログラム)として作ってしまいます。
そして、モックアップと結合してテストを行います。

えーっ、存在しない部分を作っちゃうの? そんなの大変だし、無駄になるだけじゃないの?

やってみなくては分かりません。

共同開発の場合、途中でインターフェースが変更になることが多く、一度結合しただけでは終わりません。
その後、何度も何度も自分も相手も修正を行って結合が繰り返されるため、どんどん後ろの納期が迫ってくる恐怖を味わうことになってしまいます。
その点、モックアップを作ってしまえば、結合をする前に正しく動作することを確認できます。
そして、結合したときに問題が発生しても、そのときのモックアップとの差の部分に問題が潜んでいることが分かり、解決が早くなります。

実際にやってみる

実際にモックアップを作るところをここでやってみます。
つまらないお題目で実践することもできるのですが、モチベーションが沸かないため、少しやりすぎ感はあるものの、面白いものを用意しました。

pythonでモックアップというとunittest.mockを利用するかと思われるかもしれませんが、今回は必要性が感じられなかったため利用していません。

プログラムの全体像と担当部分

自分が作成する部分を含めて、プログラム全体として、

① GUI画面からデータベースの名前・日付を入力すると
② データベースからデータを取り出して
③ データをk-means法(*3)でクラスター分析して
④ 画面に表示をする

というものを考えます。

実は小生も分析の分野にはほぼ初挑戦!
理解しきれていない部分もあると思いますがご容赦ください。

上記のうち、自分の担当する部分は、③の部分で、①、④はまだしも、②がまだできていないという状況だとします。(①、③はなくてもなんとかテストはできます)
自分の担当する部分は、クラスター分析を行うため、主要部分ではあるのですが、構造的に③ができあがるまでテストができません。

小生であれば、極めて不安になります。
しかし、モックアップを作成することで、こういった不安も解消され、自信が出てきます。

なお、分析に使ったデータは下記から得た2013年からのスーパーマーケット店舗数の推移データです。
ダウンロードしてcsv化しました。
これがどんな特徴を持つ4つのクラスターに分類されるかを確認します!

データダウンロード|統計・データでみるスーパーマーケット
3. k-means法とは、簡単に説明すると、与えられたデータの集合から、似た特徴のあるもの同士を1つのクラスター(塊)と見なし、複数のクラスターに分類する手法のことです。

モックアップの作成とテストの実行

担当部分のプログラムは以下のようにすでに出来上がっています。
このプログラムの内容の詳細に触れてしまうと、本題から随分と反れていってしまうため、ここでは書きません。
問題は、下記のソースコードのままでは、classesフォルダにdatabase.pyモジュールがまだ存在しないため、Databaseクラス(着色部)が使えないという点です。

[テスト対象プログラム]

from classes.database import Database       # データベースから読み出すモジュール
import numpy as np                          # 数値計算拡張モジュール
import pandas as pd                         # データ解析支援モジュール
from sklearn.cluster import KMeans          # KMeans法クラスタ解析モジュール

class DataClusterize() :
    def setDatabase(self,db) :              # GUIからデータベース名を指定させるメソッド
        self.dbname = db

    def setDateRange(self,dt1,dt2) :        # GUIからデータ範囲(日時)を指定させるメソッド
        self.dt1 = dt1
        self.dt2 = dt2

    def setClusters(self,n_clusters) :      # GUIからクラスタ数を指定させるメソッド
        self.n_clusters = n_clusters

    def getDatabaseRecords(self) :          # データベースからデータを取得するメソッド
        db = Database()
        db.open(self.dbname)
        self.df = db.getRecords(self.dt1,self.dt2)
        db.close()

    def clustering(self) :                  # クラスタ解析を行うメソッド
        df = self.df
        cols = df.columns
        lists = []
        for col in cols:
            lists.append(df[col].tolist())
        
        nparray = np.array(lists)
        nparray = nparray.T
        pred = KMeans(n_clusters=self.n_clusters).fit_predict(nparray)

        df['clsid'] = pred

        cls_df = pd.DataFrame()
        for i in range(self.n_clusters):
            cls_df['c'+str(i)] = df[df['clsid']==i].mean()

        cls_df = cls_df.drop('clsid')
        return cls_df
        

そこで、以下のテストプログラムのように、①、②、④のモックアップを作り、テストができるようにします。
テストプログラム本体には➀、➃のGUI部分のモックアップを組み込みました。

[テストプログラム]

import unittest as ut               # ユニットテストモジュール
import matplotlib.pyplot as plt     # 画面表示用pyplotモジュール
import matplotlib                   # 画面表示用matplotlibモジュールパッケージ

from tests.database import Database # テスト用データベースモックアップモジュール

# classes.databaseモジュールをまるごとtests.databaseとして差し替える
# 下記の順序は重要。
import sys
sys.modules['classes.database'] = sys.modules['tests.database']
from classes.dataclusterize import DataClusterize   # クラスタ分析モジュール(テスト対象)

class TestCase1(ut.TestCase):
    
    def display(self,cls_df) :   # ➃ GUI画面へ表示することをmatplotlibで代用する
        # グラフのフォントを指定(デフォルトでは日本語が文字化けする)
        plt.rcParams['font.family'] = 'MS Gothic'
        # cls_dfを転置してから棒グラフ(bar)でプロットする
        plotobj = cls_df.T.plot(kind='bar', stacked=True, title='graph')
        # X軸方向のラベルを設定
        plotobj.set_xticklabels(plotobj.xaxis.get_majorticklabels(), rotation=0)
        # 凡例をグラフの右上の外側に設定
        plt.legend(bbox_to_anchor=(1.05,1), loc='upper left', borderaxespad=0)
        # 凡例を外に出した分、グラフ領域を広げる
        plt.subplots_adjust(right=0.7)
        # 画面に描画
        plt.show()
    
    def test_1(self) :      # ➀ GUI画面からの入力を行なうことをここで行なう
        # クラスタ分析クラスのオブジェクト化
        dc = DataClusterize()
        # データベースの接続先の設定
        dc.setDatabaseConnection('localhost:5432', 'tenpo2005')
        # データ範囲(日時)の設定
        dc.setDateRange('20131001','20200609')
        # クラスタ数の設定
        dc.setClusters(4)
        # データベースレコードの読み込み
        dc.getDatabaseRecords()
        # クラスタ分析実行
        cls_df = dc.clustering()
        # 画面にクラスタ分析結果を表示
        self.display(cls_df)
    
if __name__ == "__main__" :
    # テストを実行
    ut.main()

➁のデータベースアクセス部分は、tests.database.pyとして別ファイルにしてみました。
また、実際にデータベースにアクセスするのはあまりに大変であるため、CSVファイルからの読み込みを行なう処理で代用します。

[モックアップモジュール tests.database.py]

#  ➁ データベースからデータを取り出す

import pandas as pd

class Database():

    def open(self,dbname):
        self.dbname = dbname

    def getRecords(self,dt1,dt2):
        fname = "d:\blog\mock\tests\" + self.dbname+'.csv'
        # CSVファイルを読み込む
        df = pd.read_csv(fname,encoding='utf-8')
        # データから余分な列を削除する
        del(df['集計日'])
        del(df['種別'])
        return df

    def close(self):
        return

if __name__ == '__main__' :
    db = Database()
    db.open("d:\blog\mock\tenpo2005")

テストプログラムを実行すると下記の結果となります。
実際は全都道府県データがありますが、凡例が表示しきれなくなってしまうため、一部の県を削除しています。
4つのクラスタに分類した結果、特徴が色濃く出ていることが分かります。
ただし、今回の分析はあくまでも動作確認のレベルであり、分析の内容にあまり意味はありませんので、あしからず。

まとめ

いかがでしたでしょうか。
モックアップを作成することで、他からの影響を受けずに進めることができ、目の前で動作がすぐに確認できるため、心配が軽減されることが理解いただけたでしょうか?

気持ちよく楽しいプログラミングをできるようにするためにで、ぜひとも実践してみてください。

ここに記載されていないケースや解決法についての問い合わせは、ホームページからメールで受け付けています。お気軽にご連絡ください。

0

コメント

タイトルとURLをコピーしました