#プログラミング #モックアップ #安心 #テストできない #動かせない #k-means法
テストしたくてもできない!
プログラミングにおいては、時として、動作させて確認することができない場面に遭遇することがあります。
例えば、以下のようなケースです。
・ 共同でプログラミングしていて他の人のプログラムができる前にテストしたい
・ 未入手のシステムやソフトウェアの一部を作っていてテストをしたい
このようなケースで、自分のプログラミングが先行し、他者が遅れてしまっている場合を考えます。
こういった場合、その後、プログラム同士を結合して結合テスト(*1)を行いますが、そのときに初めて動作させることになります。
この時、たいていプログラムのインターフェース(*2)が合っていないことが判明して、ただでさえ納期が短くなっている中、炎上することになります。
小生は過去に作り直しをするはめになったことがありました。。。
どうやって進めるか
まだ存在しない部分を、モックアップ(ハリボテプログラム)として作ってしまいます。
そして、モックアップと結合してテストを行います。
えーっ、存在しない部分を作っちゃうの? そんなの大変だし、無駄になるだけじゃないの?
やってみなくては分かりません。
共同開発の場合、途中でインターフェースが変更になることが多く、一度結合しただけでは終わりません。
その後、何度も何度も自分も相手も修正を行って結合が繰り返されるため、どんどん後ろの納期が迫ってくる恐怖を味わうことになってしまいます。
その点、モックアップを作ってしまえば、結合をする前に正しく動作することを確認できます。
そして、結合したときに問題が発生しても、そのときのモックアップとの差の部分に問題が潜んでいることが分かり、解決が早くなります。
実際にやってみる
実際にモックアップを作るところをここでやってみます。
つまらないお題目で実践することもできるのですが、モチベーションが沸かないため、少しやりすぎ感はあるものの、面白いものを用意しました。
プログラムの全体像と担当部分
自分が作成する部分を含めて、プログラム全体として、
① GUI画面からデータベースの名前・日付を入力すると
② データベースからデータを取り出して
③ データをk-means法(*3)でクラスター分析して
④ 画面に表示をする
というものを考えます。
実は小生も分析の分野にはほぼ初挑戦!
理解しきれていない部分もあると思いますがご容赦ください。
上記のうち、自分の担当する部分は、③の部分で、①、④はまだしも、②がまだできていないという状況だとします。(①、③はなくてもなんとかテストはできます)
自分の担当する部分は、クラスター分析を行うため、主要部分ではあるのですが、構造的に③ができあがるまでテストができません。
小生であれば、極めて不安になります。
しかし、モックアップを作成することで、こういった不安も解消され、自信が出てきます。
なお、分析に使ったデータは下記から得た2013年からのスーパーマーケット店舗数の推移データです。
ダウンロードしてcsv化しました。
これがどんな特徴を持つ4つのクラスターに分類されるかを確認します!
モックアップの作成とテストの実行
担当部分のプログラムは以下のようにすでに出来上がっています。
このプログラムの内容の詳細に触れてしまうと、本題から随分と反れていってしまうため、ここでは書きません。
問題は、下記のソースコードのままでは、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つのクラスタに分類した結果、特徴が色濃く出ていることが分かります。
ただし、今回の分析はあくまでも動作確認のレベルであり、分析の内容にあまり意味はありませんので、あしからず。
まとめ
いかがでしたでしょうか。
モックアップを作成することで、他からの影響を受けずに進めることができ、目の前で動作がすぐに確認できるため、心配が軽減されることが理解いただけたでしょうか?
気持ちよく楽しいプログラミングをできるようにするためにで、ぜひとも実践してみてください。
ここに記載されていないケースや解決法についての問い合わせは、ホームページからメールで受け付けています。お気軽にご連絡ください。
コメント