mokky14's IT diary

IT関係の仕事メモ、勉強会の感想など書いてます。

PythonからOracle接続

PythonOracle接続してデータ検索する方法のメモ。

環境

OS Python Oracle Client
CentOS 6.4 3.3.0 11.2.0.3.0

インストール

Oracleへの接続ライブラとして、cx_Oracleをインストールする。
Oracleクライアントは既にインストールされている環境を使用したので、そちらのインストールは省略。(多分以下の4つのrpmをインストールした環境のはず)

まずは、cx_Oracleインストールに必要なpython3-develのインストール。

$ sudo yum install python3-devel
読み込んだプラグイン:fastestmirror, refresh-packagekit, security
インストール処理の設定をしています
Loading mirror speeds from cached hostfile
 * PUIAS_6_computational: puias.math.ias.edu
 * base: ftp.iij.ad.jp
 * centosplus: centos.mirror.secureax.com
 * epel: epel.mirror.srv.co.ge
 * extras: centos.mirror.secureax.com
 * updates: ftp.iij.ad.jp
依存性の解決をしています
--> トランザクションの確認を実行しています。
---> Package python3-devel.x86_64 0:3.3.0-1.puias6 will be インストール
--> 依存性解決を終了しました。

依存性を解決しました

===================================================================================================================
 パッケージ                アーキテクチャ     バージョン                   リポジトリー                       容量
===================================================================================================================
インストールしています:
 python3-devel             x86_64             3.3.0-1.puias6               PUIAS_6_computational             169 k

トランザクションの要約
===================================================================================================================
インストール         1 パッケージ

総ダウンロード容量: 169 k
インストール済み容量: 532 k
これでいいですか? [y/N]y
パッケージをダウンロードしています:
python3-devel-3.3.0-1.puias6.x86_64.rpm                                                     | 169 kB     00:01
rpm_check_debug を実行しています
トランザクションのテストを実行しています
トランザクションのテストを成功しました
トランザクションを実行しています
  インストールしています  : python3-devel-3.3.0-1.puias6.x86_64                                                1/1
  Verifying               : python3-devel-3.3.0-1.puias6.x86_64                                                1/1

インストール:
  python3-devel.x86_64 0:3.3.0-1.puias6

完了しました!

続いて、cx_Oracleのインストール。

$ echo $ORACLE_HOME
/usr/lib/oracle/11.2/client64
$ sudo ln -s /usr/include/oracle/11.2/client64 $ORACLE_HOME/include
$ su
# echo /usr/lib/oracle/11.2/client64/lib >> /etc/ld.so.conf.d/oracle.conf
$ sudo ldconfig
$ pip install cx_Oracle
(途中略)
Successfully installed cx-Oracle
Cleaning up...

環境設定(クライアント環境)

自分の環境のOracle周りの設定。 LD_LIBRARY_PATHの設定は必須。 他は関係ない設定もあると思うけどメモがてら載せとく。

export ORACLE_HOME=/usr/lib/oracle/11.2/client64
TNS_ADMIN=$ORACLE_HOME/network/admin
export TNS_ADMIN
export NLS_LANG=Japanese_Japan.AL32UTF8
NLS_DATE_FORMAT='YYYYMMDDHH24MISS'
export NLS_DATE_FORMAT
NLS_TIMESTAMP_FORMAT='YYYYMMDDHH24MISS.FF3'
export NLS_TIMESTAMP_FORMAT

export PATH=$PATH:$HOME/bin:$ORACLE_HOME/bin
export LD_LIBRARY_PATH=.:$ORACLE_HOME/lib:/lib:/usr/lib:/usr/local/lib

データ取得

テーブルからデータを取得して表示してみた。

$ python3
Python 3.3.0 (default, Feb 12 2013, 17:01:04)
[GCC 4.4.6 20120305 (Red Hat 4.4.6-4)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import cx_Oracle
>>> conn=cx_Oracle.connect('scott','tiger','xx.xx.xx.xx/tns_service_name')
>>> cur=conn.cursor()
>>> sql="select * from scott.db_tbl  where rownum<20"
>>> cur.execute(sql)
<cx_Oracle.Cursor on <cx_Oracle.Connection to scott@xx.xx.xx.xx/tns_service_name>>
>>> rows=cur.fetchmany(10)
>>> print(len(rows))
10
>>> print(cur.rowcount)
10
>>> for row in rows:
...  print(row)
...
(tupleデータ10行出力)
>>> rows=cur.fetchmany(10)
>>> print(len(rows))
9
>>> print(cur.rowcount)
19
>>> for row in rows:
...  print(row)
...
(tupleデータ9行出力)
>>> rows=cur.fetchmany(10)
>>> print(len(rows))
0
>>> print(cur.rowcount)
19
>>> cur.close()
>>> conn.close()

この内容を元にして、テーブルレコード全件をCSVファイルに出力するPythonスクリプト作ってみた。

#!/usr/bin/python3

import cx_Oracle
import sys
import csv
from itertools import chain

argvs = sys.argv
argc = len(argvs)
if argc != 2:
  print('Usage: %s TableName' % argvs[0])
  quit()

table_name = argvs[1].upper()
file_name = table_name + '_data.csv'

with cx_Oracle.connect('scott','tiger','xx.xx.xx.xx/tns_service_name') as conn:
  # テーブルの列名取得
  column_name_sql = 'select column_name from user_tab_columns where table_name = :tbl'
  cur_columns = conn.cursor()
  cur_columns.execute(column_name_sql, tbl=table_name)
  columns = cur_columns.fetchall()
  cur_columns.close()
  columns = tuple(chain.from_iterable(columns))

  # テーブルのレコード全件取得
  data_sql = 'select * from %s' % table_name
  cur_data = conn.cursor()
  cur_data.execute(data_sql)
  with open(file_name, 'w') as f:
    csv_writer = csv.writer(f)
    csv_writer.writerow(columns)
    while 1:
      rows = cur_data.fetchmany(50)
      if len(rows) == 0:
        break
      csv_writer.writerows(rows)
  cur_data.close()

参考:
pythonからOracleに接続するための拡張モジュール、cx_Oracleの基本的な使い方 at nkjmkzk.net
UbuntuでPythonからcx_Oracleモジュールを使ってOracle Database 11gに接続する - 偏った言語信者の垂れ流し
Cursor Object — cx_Oracle 5.1.3 documentation

ソフトウェアテスト勉強会 ~PistMasterを使い倒す!~に行ってきました

2014/11/28のソフトウェアテスト勉強会のレポート。

今回の勉強会は、組み合わせテストの項目を簡単に作成するPictMasterの勉強。

インストール

ここからPistMasterをダウンロード。
PictMaster プロジェクト日本語トップページ - OSDN

ダウンロードしたファイルにユーザーズマニュアルが含まれてるので、その手順に従ってインストールする。

実践

基本

フォント4種類と、それぞれのフォントで太字、斜体、下線、影付きの有無を組み合わせるテスト項目。
パラメータ名と、それぞれのパラメータの値を','区切りで入力する。
(日本語入力でカンマを入力するのはちょっと面倒だけどそこは我慢)

f:id:mokky14:20141204123626p:plain

実行ボタンを押すと、a.xlsというファイル名で、以下が出力される。

f:id:mokky14:20141204123639p:plain

各項目について、2項目の組み合わせ(フォント-太文字、太文字-斜体字など)のパターン全てが出力されている。
組み合わせ項目数を変えたい場合は、環境設定->組み合わせるパラメータ数 を変更する。

f:id:mokky14:20141204124339p:plain

実行ボタン押下すると、3項目の組み合わせ(フォント-太文字-斜体字など)全てが出力される。

f:id:mokky14:20141204124512p:plain

なお、環境設定でシードの値を変えると、別の組み合わせパターンが出力される。 (シードの値を変えなければ抽出される項目は常に同じ。)

同値分割

複数の値がテストとして同じ意味を持つ場合、同値分割によりテスト項目数を減らす事が出来る。 同値は、各値を'|'で区切って指定する。

f:id:mokky14:20141204130954p:plain

出力した結果。フォント4種類の値を同値としているため、テスト項目が減っている。

f:id:mokky14:20141204131002p:plain

排他指定と結果表

Webからの入力項目の試験。 名前、メールアドレスは、入力がなければエラーとする。

名前:未入力とメールアドレス:未入力を組み合わせた試験を行うと、エラー発生時、どちらの未入力が原因でエラーになったのか分からなくなるため、各試験パターンについて、未入力とするのは、名前とメールアドレスのどちらかのみとする必要がある。 この場合、組み合わせてはいけない値は、'~'から始まるように記載する。

また、結果表を使用し、名前未入力、メールアドレス未入力の場合の結果もテスト結果として出力してみる。 結果表は「環境設定」->「結果表を使用」にチェックを入れる事により使える。

f:id:mokky14:20141204130638p:plain

実行結果。 名前=未入力とメールアドレス=未入力が組み合わさったパターンは出力されない。 また、各試験パターンについて、結果も出力される。

f:id:mokky14:20141204130647p:plain

特定条件でのみ許容するパターン

ラーメン注文のパターン試験。ただし、以下の条件あり。

  • 紅しょうがは、とんこつの場合のみ可。
  • すりおろしニンニクは、とんこつ以外の場合のみ可。
  • とんこつの場合、麺の茹で方はバリカタ、カタのみ可。

この場合、制約表により組み合わせの条件を指定し、制約条件になる方("if(トッピング==紅しょうが) then スープ=とんこつ"のif文になる方)に色を付ける。 色は何でもよい。
制約表で「~以外」という指定を行う場合、#から始まる値を指定する。今回は「#とんこつ」で「とんこつスープ以外」を指定している。
*(ワイルドカード)も使用できる。ワイルドカードは部分一致する条件の指定に使用する。
なお、残念ながらワイルドカードのみの指定はできなかった。

f:id:mokky14:20141204125344p:plain

実行結果。

  • トッピング=紅しょうがはスープ=とんこつとの組み合わせのみ出力されている
  • トッピング=すりおろしニンニクはスープ≠とんこつの組み合わせのみ出力されている
  • スープ=とんこつの茹で方はカタ、バリカタのみ出力されている

f:id:mokky14:20141204125349p:plain

「ありえない組み合わせを試験パターンから除く」ための指定なので、「該当のパターンを指定されたらエラーにする」ような試験では使用しないよう注意。

応用

問題内容。
問題には記載がないが、ブラウザのパターンも組み合わせに入れる。

f:id:mokky14:20141204125953p:plain

自分が作成したもの。

f:id:mokky14:20141204130203p:plain

他の参加者が作成したシンプルな回答。
自分が作成したものと比べると、こっちの方がすっきりして見やすい。レビューもしやすそう。

f:id:mokky14:20141204130340p:plain

PictMasterのマニュアルを見ると、他にも色々機能があるっぽい。

今まで組み合わせテスト作る時は、マトリクスで組み合わせを検討してたけど、こちらの方が簡単だし、パターンの抜けがないので便利。 次の組み合わせテストの項目作成で使ってみよう。

UX仙台 デザイナーが大事にしていること に行ってきました

2014/11/15のUX仙台のレポート。

チームで協業するための、共有のしかた (フジタジュンコさん)

過去

デザインチームが話を聞いた時点で開発期間はもう決まってたりする。
前工程で遅延が発生してても、〆切は変わらない。
デザイナーはその短い期間内で徹夜してでも頑張って終わらせる。

なのに、
「この通りに作ってくれればいいから」と言ってたのに、出来上がったら
何か違うんだよねぇ。。」と言われたり、
全部作り終わって、テストに入ろうという時になって、
偉い人がダメって言うから直して」と言われたりする。

死にたい...

なぜこうなる?

「この通りに作ってくれればいいから」の何が悪いかというと、意図を全く伝えていない。
そうなるとアウトプットもいいものが出来ない。指示が明確でないものをデザイナーは表現できない。

お客様に検証するための指標がない。
指標がないので、偉い人が「これじゃダメだよ」と言った事をそのままデザイナーに返す。

どうすれば?

全体を見ることが必要。

Webを作るといった時、製作者はWebだけ考えて良い物を作ろうとしてしまう。
ユーザは「何かをしたい」「何か欲しい」ためにWebを触る。
ユーザに価値を提供する媒体としてWebがあり、ユーザはWebではなく「Webを通して得られる体験」にお金を払う。
全体の流れの中にWebがあることを理解する必要がある。

f:id:mokky14:20141117005542p:plain

ユーザに届ける価値が一番大事。
ユーザが「お金を払っても良い」と思える価値は何か?

f:id:mokky14:20141117005607p:plain

チームでコンテクストを共有する。
全体でコンテキストを共有しないと最高のものを提供することはできない。

全体を見て協業するためにやってきたこと

インセプションデッキ

f:id:mokky14:20141117005618p:plain

良かった点

  • コンパクトなので、共有がすばやくできる。
  • キャッチフレーズを作ると、Webサイトでそのまま使える。
  • ミーティング1~2回で作れる

悪かった点

  • どの程度具体的にすればよいのかが難しい。
  • 大きいプロジェクトだと、内容がざっくりすぎて、何回も作る羽目になった。

大規模なプロジェクトでは難しいが、中規模、小規模のプロジェクトでは有用。
インセプションデッキを使用することで、ユーザが何を求めているか?
我々のサービスがどうアプローチ出来るかを共有する事が出来る。

ビジネスモデルキャンバス

良かった点

  • チーム外の活動(営業、マーケットの動き、エバンジェリストの活動等)を洗い出す事ができた。
  • 顧客にもたらす価値を共有できた。
  • コミュニケーションのポリシーまで決められた。

悪かった点

  • 時間がかかる。(以前のプロジェクトでは1週間くらいかかった)

デザインコンセプトを作る時には有効。
他にカスタマージャーニーマップも参考になる。

ペーパープロトタイピング

UI設計書の前にペーパーでプロトタイピングしたもの。
UIするデザイナーとのやりとりに使っていた。

f:id:mokky14:20141117005630p:plain

社内でテスターの人を呼んでペーパーで使い勝手をテストしてもらう。

良かった点

  • ペーパーで一旦テストしているので、後で「この画面使えない」という事はなかった。
  • テストとデザインを別立てで走らせられる。デザイナーを待たせないで済む。

悪かった点

  • 工作に時間がかかる。
  • 学習コストが高い。
  • 紙は動かないので、インタラクション設計を別にする必要がある。

画面遷移がそれほど多くないものであれば、紙に書いたものをデザイナーに渡すだけで、デザイナーは割とやれる。

気を付けている事

f:id:mokky14:20141117005716p:plain

全体を見て共有する事によるメリット

f:id:mokky14:20141117005724p:plain

f:id:mokky14:20141117005731p:plain

プロジェクトが始まった時点ではみんな「よいもの」を作りたいと思っている。
職歴、立場等で、「よいもの」がずれてくる。
「ユーザにとって」よいものを作るために上記の手法は有用。

f:id:mokky14:20141117005737p:plain

デザインワークをスムーズにする、共有のしかた (井上亜津奈さん)

デザインはふわっとしたモノととらわれがち。
f:id:mokky14:20141117005816p:plain
なぜこのデザインにしたか、デザイナーは常に答えを用意しておかなければいけない。
クライアントは説明の方にお金を払っている。

デザインの目的は課題の把握と解決。
デザインで何ができるかを考えて、具体的な方法を提示する。
主観やセンスで片付けられるものではない。

デザインの現場でよくある事

f:id:mokky14:20141117005825p:plain
f:id:mokky14:20141117005833p:plain

でも、お客さんは悪くない。当たり前の事。

お客さんに分かりやすいものを提示して誘導するのもデザイナーの仕事。
明確なイメージを一緒に探らなければ迷路に迷い込んでしまう。

まず、ビジネスやサービスの目的を理解すること。
f:id:mokky14:20141117005901p:plain

デザインに出来ない事も理解しておくこと。
「検索で常に上位に来る」とかはデザインでは出来ない。

トーン&マナーを作る

トーンとは、企業やサービスがもってる「らしさ」の事。
トーン(概念)をルール化したものをトーン&マナーという。

f:id:mokky14:20141117005934p:plain

トーン&マナーを作るときはターゲットが大切。

デザインの前に表現の方向性の共有を行う。これでデザインが楽になる。

f:id:mokky14:20141117005946p:plain

ヒアリングでは世界観を表すものだったら何でも(雑誌、サイト、ブランド等)いいので聞く。

ユーザのヒアリングに有効な手法

f:id:mokky14:20141117010002p:plain

言語マトリクス

ユーザヒアリングの中で出てきた抽象的なワードを拾って言語マトリクスを作成し、どのあたりを狙うかを考える。
競合の会社がマトリクス上どのあたりに位置するかをポイントし、そのあたりは外すという事も出来る。
お客さんも参加しやすいというメリットがある。

カラーリング

こんなキーワードで、こんなターゲットで、こんな組み合わせはどうでしょう? と提案する。
カラーは世界を決めてしまうものなので大切。

f:id:mokky14:20141117010011p:plain

イメージボード

世界観を表す画像を集めたスクラップブックのようなもの。
手間はかかる。
お客さんとイメージ共有を手っ取り早くするために使用する。

サンプルサイト

見えるものに引っ張られてしまうという弊害がある。
見せたサイトと全く同じものを作ると思われたり、イメージではなくガワの話に終始する危険性がある。
使えるかはお客さんに依る。

ワークショップ

2チームに分かれてのデザインワークショップ。
自分のチームは、ずんだPRのためのWebサイトリニューアル企画検討。
(課題内容書いた紙を持ち帰るの忘れた orz)

ワークショップの内容

  1. 依頼内容の確認。
  2. 依頼内容を元にお客様にヒアリング。(ヒアリングシート無くしたので写真なし。)
  3. ヒアリングした内容から、企画検討。
  4. プレゼンのボードを作成し、お客様(相手チーム)にプレゼン。

企画検討
f:id:mokky14:20141129024922p:plain

良かったところ

  • 企画検討のとき、アイデアを各自が発言しながら付箋に書いて貼っていくのは良かった。(誰か一人が記載するより早い。人の発言を聞きながら自分の手を動かせる)
  • 企画検討で、対象の情報をググって、アイデアのヒントになる情報を探すのは有効。(「ずんだは仙台七夕あたりからお盆までが繁忙期」という情報から、七夕祭りとファッションショーを関連付ける案が出た。)
  • いまいちだな、と思ってもとりあえず出してみる。他の人がそのアイデアを膨らませてくれるかも。
  • イデア出しのとき、「否定しない」事は大事。人のアイデアで「いまいちだな」と思っても、「このアイデアの活かせそうなところは。。」という方向で考えて、アイデアを発展させることが出来た。

悪かったところ

  • お客さんへのヒアリングが難しかった。抽象的なイメージを聞くためにどんな質問したら良いか分からなかった。今ブロク見返して、言語マトリクスとか使ってみても良かったと思ったり。

自分のチームで作成したプレゼンボード。
f:id:mokky14:20141116235656p:plainf:id:mokky14:20141116235711p:plainf:id:mokky14:20141116235721p:plainf:id:mokky14:20141116235732p:plainf:id:mokky14:20141116235855p:plain

作成した後に思ったのが、「ユーザの発言全てに応えようとはしなくて良い」事。
お客様の色々な立場の人が、それぞれの立場から意見を出してきたら、その中には相反する要望、実現出来ない要望、単なる思いつきの要望も入ってるはず。
なので、要望全てに応えようとするのではなく、要望をヒントに方向性を決めて、その方向性に沿って提案をする事が大事。
自分も含めて、プログラマーは言われたことは全て実現しないといけないという考えになりがちなので、この視点は意識しないといけない。

デザインにもアジャイルの手法が有効な事が分かったのは面白かった。

アジャイルサムライ−達人開発者への道−

アジャイルサムライ−達人開発者への道−

IntelliJでスネークケースとキャメルケースの切替

IntelliJで、変数のsnake_case⇔CamelCaseの切替(Eclipseだとctrl+alt+kで出来る)をどうやってやればよいか調べたのでメモ。
Plugin入れないとダメらしい。

試した環境は、IntelliJ IDEA 12.1.6、Windows7 Professional。

導入手順
  1. JetBrains Plugin Repository :: CamelCaseをインストールしてIntelliJ再起動。
  2. 切替する単語にカーソルのせて、Shift+Alt+uで切替。押す度に切り替わる。

is_readable という単語を切り替えてみると、

  • IS_READABLE
  • IsReadable
  • isReadable
  • is_readable

というように切り替わる。

Pythonのデフォルト引数にハマった

Python初心者がハマるポイントにしっかりハマってしまったので記録残しとく。

Pythonの関数引数にはデフォルト値が指定できる。
時刻指定する関数で、引数省略時は現在時刻を取得する関数を作ろうとした。

import time

def tim(t=time.time()):
    print(t)

if __name__ == "__main__":
    tim()
    time.sleep(1.25)
    tim()
    time.sleep(1.4)
    tim()

が、このtim関数を実行すると、同じ時間しか取得されない。

C:\>python.exe time_func_test.py
1414077198.46061
1414077198.46061
1414077198.46061

このデフォルト引数の値はモジュール評価時に決まるようで、一度関数を実行すると、後は決まった値が使用され続けるらしい。
上記の関数ではやってないけど、デフォルト引数にリストなどの可変オブジェクトを渡して、処理内でリストを更新すると、次の関数コール時は更新したリストが渡されてしまう。

元々やりたかった処理は、以下のような処理で実現した。

import time

def tim(t=None):
    if t is None: t=time.time()
    print(t)

if __name__ == "__main__":
    tim()
    time.sleep(1.25)
    tim()
    time.sleep(1.4)
    tim()

実行結果。毎回値が変わるようになったのでやりたいことは出来たっぽい。

C:\>python.exe time_func_test.py
1414078025.345443
1414078026.595514
1414078027.997595


参考:
Python初心者によるPythonのいいところ、はまりどころのまとめ - Webtech Walker

ExpectedExeptionを使ってみる

JavaでExceptionが発生する事を検証するテストは以下のように書く事が出来る。

    @Test(expected = IllegalArgumentException.class)
    public void Exceptionの検証() {
        throw new IllegalArgumentException("このメッセージは検証できない");
    }

ただ、このテストケースでは、意図したExceptionが発生する事は検証できるが、そのExceptionの内容の検証を行う事が出来ない。
Exceptionの検証にExpectedExceptionクラスが使えるという情報を貰ったので使い方を確認。

使い方

  1. @Ruleアノテーションを付与し、ExpectedExceptionクラスのインスタンスを取得
  2. テストケースの先頭で、Exceptionについて検証する内容を設定
  3. Exceptionが発生する処理を実行

サンプル

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;

import static org.hamcrest.Matchers.endsWith;

public class ExpectedExceptionTest {
    // @Ruleを付加するフィールドはpublicフィールドとする
    @Rule
    public ExpectedException expected = ExpectedException.none();

    @Test
    public void ExpectedExceptionを使ったException検証() {
        // 検証する内容を設定
        expected.expect(IllegalArgumentException.class);
        expected.expectMessage("sample");   // 部分一致検証
        expected.expectMessage(endsWith("exception"));

        // Exceptionが発生する処理を実行
        new SampleClass(null);
    }

    static class SampleClass {
        SampleClass(String str) {
            if ( str == null ) {
                throw new IllegalArgumentException("sample exception");
            }
        }
    }
}

このコードで、Exception#getMessage()の内容を検証する事が出来る。
なお、ExpectedException#expectMessage(String)メソッドは部分一致の検証である事に注意。

JUnit実践入門にも載ってた。

JUnit実践入門 ~体系的に学ぶユニットテストの技法 (WEB+DB PRESS plus)

JUnit実践入門 ~体系的に学ぶユニットテストの技法 (WEB+DB PRESS plus)

TDDBC仙台 4thに行ってきた

昨年に続きTDDBC仙台に参加してきました。
@t_wadaさん、スタッフ、および参加者の皆さん、どうもありがとうございました。

当日のtogetter
TDDBC仙台 4th - Togetterまとめ

基調講演

@t_wadaさんによる基調講演。
講演資料は後日SlideShareにアップするとの事。

TDDの目標

f:id:mokky14:20141013042949p:plain
動作するキレイなコードがTDDの目標。
テストコードが存在することで、改善が可能になる。

ソフトウェア工学は予測性が低い。コードを書き始めることで初めて問題に気がつくことが多い。
なので、完璧な設計をしてから実装を始めるのではなく、とりあえず実装し、きれいなコードにするのはその後にする。TDDはその手助けをしてくれる。

TDDのサイクル

f:id:mokky14:20141013043644p:plain

  1. 目標を示すテストコードを書く
  2. テストを成功させるプロダクションコードを書く
  3. プロダクションコードをリファクタリングする

このサイクルが重要。
納期等の理由でリファクタリングされなくなる事があるけどちゃんとやりましょう。

テストコードのメンテナンスコストが高いと、「テストコード修正が大変だからプロダクションコードの改造はしない」という本末転倒な事になる。
なので、テストコードにもリファクタリングが必要。
プロダクションコードと同じく、テストコードもDRYにする。コピペしまくったりとかやってはいけない。

TDDを導入することで、実装時間は2割弱増えるが、その後の不具合検出数が減るため、トータルでの開発工数は減る。

TDDの対象範囲

f:id:mokky14:20141013042939p:plain
テストの目的は対象によって異なる。
TDDはDeveloper Testing。開発者の開発促進が目的。

f:id:mokky14:20141013184616p:plain
TDDの"T"はTestというよりCheckingに近い。(TDDはプロダクションコードが動作する事の確認でしかないため)
要件のテストとして、BDDという方法も出て来ているが、RSpecを使用したBDDとScenarioを使用したBDDの二派に別れているのが現状。

テストを動かすだけでは品質は上がらない。テストは品質を明確にするだけ。
品質を高めるのはリファクタリング
体重計に乗っただけでは体重は減らないのと同じ。

なぜTDDをするか

f:id:mokky14:20141013043346p:plain
「動いているコードは触るな」とは今は言えない。
コードを触らなくても周り(OS、フレームワーク等)が変わっていく。直さざるを得ない。
何もしなければコードは腐っていく。

テストコードがあることで、コードへのフィードバックが即座に得られ、書いたコード、これから書くコードに自信が持てる。

TDDライブデモ

@135yshrさんと@nnasakiさんによるgo言語によるライブデモ。
go言語は全く知らなかったけど、@135yshrさんのIDE(Sublime text)の使いこなしに感心したり、「テストコード書くのにコピペは使わないようにしてる」の発言になるほどと思ったりしながら見させて頂きました。

昼飯

はらこめし。うま。
http://instagram.com/p/t_xzB5K_OL/

ペアプロ

昨年に続きJavaで参加。
Pythonやりたかったけどペア居なかった。。

課題と自分らのチームで実装したソース

TDD Boot Camp(TDDBC) - TDDBC仙台04/課題
実装ソース

感想KPT

Keep
  • IntelliJコーディング楽しい。
  • 「あれどうやるんだっけ?」と詰まった時に備えて「JUnit実践入門」持っていったのは正解だった。
  • GitHubでコード共有して演習進めたのは、お互いに自分のマシンが使用できて効率良かった。
  • コードレビューで、設計や改造について、色々なチームの意見が聞けたのが面白かった。
Problem
  • GitHubの使い方あんまり分かってなくてペアの方に世話になりっぱなしだった。
  • テストコードのリファクタリングやったとき、リファクタリング後のテストが動作するかの確認が雑だった。
  • 仕様追加時、作成済みテストコードの作り直しが多く発生した。実務で既存コードの修正量を抑える方法をもう少し考えた方がいいかも。
Try
  • ExpectedExceptionでExceptionの検証を行うテストが書ける事を教えてもらったので、後で機能確認しておく。
  • 残りの演習やってみる。

QAとか

和田さんへの質問と回答。

Q) 基調講演の中で、プロダクションコードとテストコードの比率が同じになるような例が出ていたが、テストコードはそんなに減らせるものなのか?
A) プロダクションコードとテストコードの比率が1:1になるようにリファクタリングし、プロダクションコードとテストコードの比率が1:1~1:2の範囲に収まるようにする。
この比率を超えるようならテストコードの見直しが必要。

Q) テストコードで、Mockは使うべきか、使わないべきか?
A) Mockは使う派と使わない派がいるが、@t_wadaさんはMock使わない派。
実物のコードが使えるなら、出来るだけ実物を使うようにしている。実物のコードを使うことで時間がかかるのは仕方ないと考えている。

最後に

テスト書きましょう。
f:id:mokky14:20141011110405p:plain