この記事はGaiax Advent Calendar 2015 - Qiitaの12日目です。
こんにちわ。ガイアックスのQE(Quality Engineer)チームの @sakaimo です。今回はQEチームについて紹介したいと思います。
ガイアックスのQA(Quality Assurance)チームの歴史
ガイアックスには2009年からQAチームがあります。「開発者とは別に、テストを専任で行う人がいる」というのがポイントです。 このあたりは WebのQAを5年間運営してみた で紹介しましたのでご興味あれば御覧ください。このチームは主に「手動テスト」で「意図したように動作するか」「ユーザーに不利益になる動作をしないか(ユーザビリティ含む)」を確認するのが役割です。当時は開発チームが複数あり、必要に応じてQAチームからメンバーをアサインしてテストを実施する、というスタイルでした。
2015年から会社全体として「事業別組織」になったことにより、QAのメンバーはそれぞれの事業に所属することになりました。また、QAがいない事業も存在するようになりました。
技術の方に入っていきたい
...という体制変更があり、このタイミングで「技術を使ったテスト」にチャレンジしてみようと思い、2015年7月からQEチームとして活動しています。これまで「別」だったDevとQAの間を繋ぐというか、どっちもできるというか、そゆ役割になりたいなと。特にここ2,3年で弊社でもアジャイルとかスクラムのプラクティスを取り入れるようになって来ており「チームで品質も担保する」という流れになってきているのも要因の一つです。チームといっても私と新卒エンジニアの2人ですけどね!
何をやってるの?
ミッションは「ソフトウェア品質と開発生産性を向上させる」です。受け取り手によっていろんなイメージがされると思いますが、現在のテーマは「コードの品質」と「見える化」です。
コードの品質とは、例えば主観的には「読みやすい、理解しやすい」と品質が高いと言えそうですし、客観的には「サイクロマチック複雑度が低い」とか「コードカバレッジが高い」と品質が高いと言えそうです。では、そのようなコードをどうやったら書けるか、というような取り組みです。
見える化については、上記の複雑度やカバレッジのようなコードメトリクスを「自動で、継続取得して、グラフ表示する」ことで、その時点の品質に加えて「改善効果を」見える化していく、という取り組みです。
コード品質の取り組み紹介
QEメンバーの新卒エンジニア ShoichiroKitano が大学時代にソフトウェア工学を学んでいる間にTDD依存症になったようで、今もオブジェクト指向大好き人間で「そのノウハウをWeb開発の中にどうやって取り入れていくか」で力を発揮してくれています。具体的にはコードレビューやペアプロを通して、オブジェクト指向やデザインパターンを駆使したコードの書き方、リファクタリングの仕方を広めています。
今回はその一例を紹介します。(Qiita:Teamより引用)
<引用ここから>
単体テスト書く必要がある部分
まずはどこに対して単体テストなるものを書く必要があるのかを説明します。 ここでの単体テストの定義は以下のような分類に則ったものです。
基本的に単体テストは、テストしたい対象の関数(メソッド)内にロジックが含まれている場合に書きます。早い話が条件分岐が存在するならば、書く必要があります。それ以外にも書く理由はちょこちょこありますが、分岐の構造が存在する場合はマストだと思った方がよいです。
今回の対象
以下に嫁の名前を受け取って、任意の旦那の名前を返すよな関数があったとします。また、この関数は$yomeの値が想定している値でなかった場合は例外を投げるような実装にしています。
package SazaeSan; sub husband_of { my ($class, $yome) = @_; return 'masuo' if ($yome == 'sazae'); return 'norisuke' if ($yome == 'taiko'); return 'namihey!' if ($yome == 'fune'); die 'forgetting the wallet exception'; }
こいつをテストしようと思うと、以下のようなテストを書く必要があります。
use Test::More; use SazaeSan; use Try::Tiny; subtest 'サザエの夫はマスオ', sub => { is(SazaeSan->husband_of('sazae'), 'masuo'); }; subtest 'タイコの夫はノリスケ', sub => { is(SazaeSan->husband_of('taiko'), 'norisuke'); }; subtest 'フネの夫はナミヘイ!', sub => { is(SazaeSan->husband_of('fune'), 'namihey!'); }; subtest '存在しないキーを受けたら例外を投げる', sub => { try { SazaeSan->husband_of('tama'); fail; } catch { pass; }; }; done_testing;
こんなしょぼのにいちいちテストかかんわ〜い!て人もいるかと思いますが、リポジトリへのpushの条件がc1が100%とかそんな感じだった場合は、結局どこかしらから自動テストを実行できるようにする義務が発生したりするので、そうも言ってられない場合があります。 かといって、ハードコードされた値のためにテスト書くのもなんだかナンセンスな感じしますし、この状態だとフラグの種類が増えるたびに辛くなりそうです。できるだけテストを書かずに終わらせたいところです。 こういったロジックに対しては多くの言語で実装されているマップ型(って勝手にいってるけど一般的かは不明)を使うことで自動テストが必要なロジックを減らすことができます。perlではハッシュというデータ型で実現されています。
マップ(ハッシュ)を使って改善する
ハッシュはキーを受けてそれに紐づく値を返すことが「保証されている」データ型です。保証されているって素敵な響きです。つまりは再利用可能な便利な道具なのです。しかも広く使われているため、ほぼほぼ確実に正常に動作するでしょう(コンパイラにもバグがあるので100%ではないです)。 さてどんな風に使うかというと、以下の通りです。
package SazaeSan; my $MARITAL_RELATIONSHIP = { sazae => 'masuo', taiko => 'norisuke' fune => 'namihey!' }; sub husband_of { my ($calss, $yome) = @_; my $danna = $MARITAL_RELATIONSHIP->{$yome}; return $danna if $danna; die 'forgetting the wallet exception'; }
if文が1つになりましたね。分岐構造が減りました。とゆーことはテストの方も上の実装に合わせて変化します。単体テストに関しては以下のテストを書けば十分にこの関数の挙動が正しいことを保証できます。
use Test::More; use SazaeSan; use Try::Tiny; subtest '嫁の名前を渡すと旦那の名前を返す', sub => { is(SazaeSan->husband_of('sazae'), 'masuo'); }; subtest '存在しないキーを受けたら例外を投げる', sub => { try { SazaeSan->husband_of('tama'); fail; } catch { pass; }; }; done_testing;
テストを2に減らすことができました(∩´∀`)∩ワーイ。 1つ目のテストの名前を変えていますが、これはロジックが変わったことでテストしたいことが変化したためです。さっきまでは「各フラグに紐づく文字列が返ってくること」をテストしていました。が、変更後は「ハッシュに入ってる値を返す」といった非常に単純なことのみテストすれば良くなったわけです。
</引用ここまで>
他にも実際のプロダクトコードを例にして、リファクタリングや設計についての改善案を提示してもらってたりします。
まとめ
QAとか品質とかテストに関わってる人も、開発技術が分かる/使える ほうが楽しいと思うんですよね。私自身は「開発者」としてはまだ役立たずですが、テストの世界の知識・経験を持って、かつ技術を使って「ソフトウェア品質と開発生産性を向上させる」ことができるチームにしていきます。自分が書くこともあれば、開発者を支援するスタンスも含めて。
最後にお知らせ
こんなQEチームのお仕事に興味がある人を募集中DEATH!いっちょこーい! Webサービスを技術でテストできるQAエンジニア募集!
明日は我らがReactio兄さん @norinux の登場です。本人はもちろんの事、こどももちょーイケメン。