読者です 読者をやめる 読者になる 読者になる

こいばな - riskriskと時々鼻メガネ -

正式名称は「どすこい!鼻メガネ会長のいつでも土俵際!」です。ソフトウェア開発に関することを書いています。

JUnitでMockしたい(Mockito)

Junit使ってて、Mock使いたくなったので、Android環境でのJunitテスト環境に
Mockitoを入れてみました。

入れ方自体は簡単で、幾つかjarをlibsに入れるだけで動きます。
libsにjarを入れておけば、勝手に組み込まれてくれるので、それを利用します。

まず、下記の3つのjarをダウンロードしてきます。

Mockito本体

mockito - simpler & better mocking - Google Project Hosting https://code.google.com/p/mockito/

ここから、mockito-all-1.9.5.jar を落としてきます。

それから、Android上で動かす場合、Dailvik VMAndroid用JavaVM)に対応した
ライブラリである必要があるわけで、Mockitoそのままだとよろしくないため
そこら辺を上手く解決してくれる、dexmakerを入れます。
(説明間違えてたらごめんなさい)

dexmaker - Programmatic code generation for Android. - Google Project Hosting http://code.google.com/p/dexmaker/

ここから、dexmaker-1.0.jar と dexmaker-mockito-1.0.jar をダウンロードします。

ダウンロードしてきた3つのファイルを、libsに入れます

f:id:riskrisk:20140211220255p:plain

パッケージエクスプローラーはこんなかんじになります。

あとは、コードに

import static org.mockito.Mockito.*;

のimportを書けば、使えるようになります。

クラスに対して

全体をMockする場合は、 mock()
部分的にMockする場合は、spy()

を利用します。

サンプルコードはこんな感じ

import android.util.Log;
import junit.framework.TestCase;
import static org.mockito.Mockito.*;

public class MockSample extends TestCase {

	private final static String TAG = "MockSample";
	
	protected void setUp() throws Exception {
		super.setUp();
	}

	protected void tearDown() throws Exception {
		super.tearDown();
	}

	public class TargetClass {

		public void printA() {
			Log.d(TAG, "print A");
		}
		
		public void printB() {
			Log.d(TAG, "print B");
		}
	}
	
	public void testMockAndSpy() {

		TargetClass targetMock = mock(TargetClass.class); // Mock
		TargetClass targetSpy = spy(new TargetClass()); // Spy
		
		// Mockは 全部Mockされる
		Log.d(TAG, "Mock");
		targetMock.printA();
		targetMock.printB();
		
		// Spyは部分的にMock出来る
		Log.d(TAG, "Spy");
		doNothing().when(targetSpy).printB();
		targetSpy.printA();
		targetSpy.printB();
	}
	
}

ログは、こんなかんじに出ます。

02-11 13:18:55.254: D/MockSample(9243): Mock
02-11 13:18:55.285: D/MockSample(9243): Spy
02-11 13:18:55.295: D/MockSample(9243): print A

Mock側は全部Mockされたので出力なし
Spy側は、printBだけMockしたのでprintAだけ表示されます。

呼ばれたことの確認とか、呼ばれた時の振る舞いを定義するとかは、また後日。

前記事のおまけの話

前の記事のおまけで、assertEqualsを使う場合に、expect側のequalsが
使われるてるんだよねぇって書いたんですが

それについてTwitterにて、ご意見もらえたのでまとめておきます。

そうそう、それはそうなんですよね。
ただ、どっちが使われるのか見えないから、なんかバグると見つけづらいし
なんか気持ち悪かったんですよね。

expect側が判断するのが正しいっぽいよねって話の理由として

コレきいて「あぁ」と思ったのは、expect側はTest側の持ち物で、
actualは、実際に動作させた結果なので、テストが動かしてみた結果なんですよね。
こうなってほしいとTestが定義している以上、必ずオブジェクトは存在するし
同じであることを定義するのはexpect側だなぁと思いました。

なんか少し理解が深まった気がする。

JUnitのassert

最近Javaで開発してるので、Junitつかってテスト書いてるんですが
assertの種類を理解してなかったので、テストコードを作成してみました。

Junitのテストクラスに直接突っ込めば動きます。
ちなみにAndroid上で動かしてたのでLogクラスを一部使ってます。
Androidじゃないところで動かすなら、適当にSystem.out.printlnあたりに書き換えてください

やってみて興味深かったのは、assertEqualsでオブジェクトの比較を行う場合に
expect側のequalsが使われるという事。
継承されたクラスで比較するときに、この辺りに手が入ってると面倒なことがあるかも?

C++だと、文字列みたいな良く比較するようなオブジェクトは、
==演算子オーバーロードされてて、普通に比較できるので
equalsに違和感あるんだよなぁ
(最初==で比較できると思っていてドハマりしたのは内緒です)

以下、Assertのテストプログラム

public void testAssert() {

	// プリミティブ型は、そのまま使える
	assertEquals(true, true);
	assertEquals((int)1, (int)1);

	// オブジェクトは、equalsで比較される
	assertEquals(
			new Object() {
				@Override
				public boolean equals(Object o) {
					Log.d(TAG, "call lhs equals.");
					return true;
				}
			},
			new Object() {
				@Override
				public boolean equals(Object o) {
					Log.d(TAG, "call rhs equals.");
					return true;
				}
			});
		
	// 真偽の判定
	assertTrue(true);
	assertTrue(1 < 2);
	assertFalse(false);
	assertFalse(1 > 2);
	
	// インスタンスの有り無し
	assertNull(null); // 中身がnull
	assertNotNull(new Object()); // インスタンス有り
		
	// 参照先のチェック
	Object expectObject = new Object();
	Object actualObject = expectObject;
	assertSame(expectObject, actualObject);	// 同じインスタンス
	actualObject = new Object();
	assertNotSame(expectObject, actualObject); // 違うインスタンス
}

おまけ

expect側のequalsが使われるとすると、こんなコードにすると
どちらをexpectに置くかで成功と失敗が変わるっていう。
意味があるかは別として、こういうとこでバグると見つけるの大変そうだなぁ

private class SuperClass {
	public Integer a = 0;
	public Integer b = 0;
}

SuperClass classA = new SuperClass() {
	@Override
	public boolean equals(Object o) {
		if(o instanceof SuperClass) {
			return a == ((SuperClass)o).a;
		}
		return false;
	}
};
	
SuperClass classB = new SuperClass() {
	@Override
	public boolean equals(Object o) {
		if(o instanceof SuperClass) {
			return b == ((SuperClass)o).b;
		}
		return false;				
	}
};
	
public void testAssertEquals() {
	
	// aは同じ値
	classA.a = 100;
	classB.a = 100;

	// bは違う値
	classA.b = 200;
	classB.b = 300;

	assertEquals(classA, classB);
	assertEquals(classB, classA); // こっちは失敗するよ
}

Androidのユニットテスト

最近、Androidをやることになったわけで、いままでほぼ触ったことの無い
Javaさんに触れる機会を貰いました。
プログラムとしてはそんなに難しいとは思わないのだけど、パッケージだったり
インポートだったり、Jarだったり、そんなところで色々悩まされています。

で本題ですが

作るからには、ユニットテストをやるってことで色々調べ始めました。
まずビックリしたのがEclipse経由でユニットテストをするのに、なぜかActivityが必要っていう。

そもそもユニットテストするのに、なぜActivityに縛られるのか疑問だけど
そういうもんだと理解することにしました(調べた限り、そういうのしか出てこない・・・)

悔しがってもしょうがないので、テストを実行するところまで。
あと、別にActivityのテストしたいワケじゃないので、Activityに縛られない
Junitを使ったテストについてまとめておこう。

ユニットテスト環境の作り方

Androidのインストールとか

このへんは、探すと山ほど出てくるので。
Eclipse入れて、Android-sdkぶっこんで・・・)

Targetのアプリケーションを作る

あまり気にせず、Target用のアプリケーションを作ります。
Activity自体にあんまり意味はなくて、とりあえずモジュールのユニットテストしたいだけなので。

上部メニューから「ファイル」→「新規作成」→「その他」を選んで

Android アプリケーション・プロジェクト」を選んで
f:id:riskrisk:20140202191806p:plain

さっくさっくと、Activityを作ります。

f:id:riskrisk:20140202191944p:plain

f:id:riskrisk:20140202192051p:plain

出来上がったActivityのサンプルをエミュレータあたりで実行して
なんか立ち上がればOK

実行ボタン押して、「Androidアプリケーション」
f:id:riskrisk:20140202192429p:plain

こんなかんじで、立ち上がるよ。
f:id:riskrisk:20140202193206p:plain

テスト用のアプリを作る

ここからが本番。
前項で作ったアプリケーションに対してテストを作成するよ。

さっきと同じ感じで
上部メニューから「ファイル」→「新規作成」→「その他」を選んで

Android テスト・プロジェクト」を選ぶよ。
f:id:riskrisk:20140202194257p:plain

テストプロジェクトの名前は適当で。

f:id:riskrisk:20140202194620p:plain

対象のアプリケーションにさっき作ったActivityを選択します。
f:id:riskrisk:20140202215415p:plain

で、ここまで出来ると、ほぼテスト環境が完成という。

実際にテストを書いてみる

実際、TargetActivityに書いてあるimportが可能なクラスなら、何でもテスト可能です。
なんでかというと、Testアプリのビルドパスに、TargetActivityが指定されてるから。

f:id:riskrisk:20140202215739p:plain

試しに、テストを書いてみます。

まず、TargetTestを右クリックして、「新規」→「Junitテストケース」を選択
テストクラスを作ります。
f:id:riskrisk:20140202220352p:plain

こんなかんじのコードを。

package com.riskrisk.test;

import junit.framework.TestCase;

import com.riskrisk.Calc;

public class TargetTest extends TestCase {

	public void testPlus() {
		Calc calc = new Calc();
		assertEquals(3, calc.plus(1,2));
	}
}

当然テストしかないから、Calcクラスを作るんで
TargetActivityに、Calcクラスを。

package com.riskrisk;

public class Calc {

	public int plus(int a, int b) {
		return 0;
	}
}

こんな感じ。

出来上がったら、TargetTest側で、「Android JUnit Test」を実行してみると

f:id:riskrisk:20140202224101p:plain
こんなかんじで失敗するから

コードを修正してみる

public class Calc {

	public int plus(int a, int b) {
		return 3;
	}
}

そうすると、こんな感じでテストが通るってさ。

f:id:riskrisk:20140202224353p:plain

あとでMockの話も少し書こう

第19回 #TFSUG Visual Studio マシュマロチャレンジ!! に参加してきた。

マシュマロ・チャレンジやってきたよ。
http://www.naturalsoftware.jp/blog/8310:「第19回 #TFSUG Visual Studio マシュマロチャレンジ!!」を開催します

講師の関(@fullvirtue)さん、TFSUGスタッフの皆さん。素晴らしい経験をありがとうございました。

もともと、存在は知ってたけど、一度もチャレンジしたこと無かったので
ワクワクしながら、品川へ。

概要として、ウチのチームは3人でした。
どの方も、一度もあったこと無い感じだったので、その場で結成されたチームで
どこまで作れるのかという不安と期待で胸いっぱいでした。

なんだか知らんのですが、リーダー誰にする?っていったら
「よし、お前だ」と 2人から指差されたので私がリーダーでした。

さて、前置きはこの程度で、本編です。

マシュマロ・チャレンジ本編

一度目
途中まで作るも、接続部分の弱さ、バランスの悪さで自立せずに倒れました。

記録! 0cm!

仕事する人間として、残念すぎる感じですねw

タイムアップいっぱいのタイミングで、小さいやつでも作っておけば
記録は残ったというのに。

実際に仕事をしていて、期限に間に合わないと分かったタイミングで
なにかしら動くレベルのものに調整するのはよくあることだけど
時間のマネジメントができていないからなのかなと。

時間のマネジメントの観点でいくと、初回チャレンジのタイムテーブルは
非常にアバウトで 全体で18分ある作業時間を

最初の10分で、どんなタワーを立てるか、どういう構造にするかを検討
残りの8分で、実際に何かを作ろう

ということにしていました。

コレをやった結果、8分ギリギリで塔の上にマシュマロを置くことになり
ボキっとマシュマロアンテナが外れて崩れて・・・
(悲しさに明け暮れて、他のチームのタワーが輝いて見えて、自分たちの
残念タワーの写真は撮りそびれました)

・・・・・

見事なまでの失敗例。

で、ここでとある動画を見るタイムがあり・・・
自分たちがやった失敗を全て見透かされw
http://www.ted.com/talks/lang/ja/tom_wujec_build_a_tower.html

で、

2回目。

ここで僕らのチームは目標を立てます
今回は、記録を必ず残そう!

タイムマネージメントは、実際更にアバウトになった。
理由としては、まず基礎の構造を作って、マシュマロタワーを立てる。
これを拡張していくことで記録を作ることにした。
なので、常にタワーがあって、それに継ぎ足していく感じ。

実際、この試みは成功で、最初の構造物は
マシュマロに2本束にした柱パスタを3箇所に刺す
さらに、2本束の間に、となりの柱と繋ぐ梁パスタを渡す。
梁は柱と紐で結ばれ、崩れなくなる。

これで、マシュマロと梁で柱が安定して、ちょっとやそっとじゃ崩れない
パスタタワーが出来上がる。

この時点で、5分程度

ここから先は、タワーの足を継ぎ足す作業を繰り返して
安定して立つことができなくなりそうなところまで継ぎ足していきました。

出来上がったタワーがこちら。

f:id:riskrisk:20130708213446j:plain

この時点で大体13分ぐらいで5分ほど余る形でした。
このあと、更に記録を伸ばすために、頂点のマシュマロを外して
アンテナ状にしたマシュマロで高さを稼ぐ案も出たのですが
私が頑なに拒否しました。

ぼくが頑なに拒否した理由は、最初に立てた目的が記録を出すことだったからで
そこで、冒険をして塔を崩すのだけは避けたかったので。
一応説明したつもりだったけど、伝わったのだろうか・・・

結果としては、59cmの塔が出来上がり、記録を残すことが出来ました。

まとめと感想

1回目と2回目で決定的に違ったのは、

・明確な目的を立てたこと

1回目の目標は、塔を立てること で
それがどれぐらいの高さのどんな形のどんな塔で、どの程度安定しているの?
というのが抜け落ちてました。
とりあえず塔が立てれば良いっていう、とてもアバウトなもので
結果として、全員が無謀なチャレンジを繰り返し、結果崩れました。

2回目の目標は、記録を残すこと
そのために、低くてもいいから安定した物を作ろう ということで作り始めました。

・一回目の失敗やチャレンジから学んだことが大きい

一回目の教訓があり安定させるために必要な構造を想像できていたことが大きかったとおもいます。
2本で柱にする案は、一回目のマシュマロアンテナ案の派生だし、3本の柱にして梁を渡すのは
ほかのチームのマシュマロタワーで、横渡しのパスタが有るのを見ていたからです。

結果としては一番には全然届いていないけど、一回目と二回目で
チーム自体が明らかに成長していることが分かったので、とても清々しい気分でした。
実際、事前勉強とか全くせずに挑んだので、何が何だから分からん状態から
チームで協力すると、ここまで作れるっていうのを体験できるっていうのは、珍しいなぁっておもいますw

またやりたいかといわれると、何か知っている状態でやるのであれば、
自分の知識を元に、こういうのはどうか?とかこうすると安定するとかのプレゼンをしながらになると思うので
また違った楽しさがあるのかと思うと・・・・

あとはまぁ、反省点として、高さにチャレンジすることが出来なかったことと
時間が5分 全体の1/4程度も余ってしまったが、そこから更に一歩進めなかったこと
目標と反したことになるってのはあるけど、他に何が出来るか思いつかなかったのは反省かなとおもいます。

なにはともあれ、とても楽しい時間を過ごせました、行ってよかったTFSUG

日本鼻メガネの会やってないなぁって話になって

日本鼻メガネの会 6代目 を開催しました。

6月4日 日本鼻メガネの会 6代目
http://kokucheese.com/event/index/95314/

とはいえ、参加者は三人(ちぇんわとこうちゃん)ですけど。

こうちゃんの愚痴を聞いたり、ちぇんわさんがこうちゃんをいじめたりしてました。

っていうか、7回目やったら、だれかくるんか?
とりあえず、適当に人集めて飲み会やればいいのかな。
# 意外とそれのほうが、需要あったりして・・・

第12回 #TFSUG :TOC探究者のプロセス運営 に行ってきた。

コレに行ってきました。
遅刻したけどね・・・

今回は、

  • しばやまさん(@) さんの プロダクトオーナー の話
  • ちぇんわ(@) さんの、考え方 の話

どっちも面白かった。

相変わらず、ログを取ることを諦め聴きに徹してたので
内容はTogetterとか、発表者の方がスライド公開をしてくれるのを待ちましょう。

Togetter - http://togetter.com/li/376633

「プロダクトオーナーシップ」:SHIBAO800 さん

プロダクトオーナーの方は、いったい何を持ってプロダクトオーナーなのかの話。

こんなPOはいやだ は、あるあるってわけじゃないけど、よく聞くなーって

  • 定額食べ放題と勘違いしている
  • 色々ついていると、凄いと思っちゃう
  • リリースのマイルストーンしか決めない
  • プロダクトバックログを整理しない
  • 受け入れ基準を後出しする

僕がコレを聞いて思ったのは、しばやまさんも言ってたけど
ゴールデン・サークルの「What」だけを見ている状態なんだなって感じました。

出来るだけいっぱい機能がついてて、製品が期間内に出ていって、
謎だろうがなんだろうか、製品さえ出来れば、それで良し。
しかし、実は使えないことが分かると、コレが出来ないとダメだと言う

こりゃあいかんと思いますw

作る側の視点で、「なんでこんな機能いるんだろ・・・」って思うことがありますが
そんな時に、「本当にコレ必要ですか?」と聞けたら健全だなって
同じように、「どー考えても、この機能が必要だと思うんですけど・・・」とか

気になったことで、プロダクトオーナーシップが揃ってるPOが良いPOって
ことなのは分かるのですが、何も全てをPOがやる必要ないよなぁとも思いました。

僕が思うチームでやることの利点は、一緒に進む仲間がいることで
決定はPOがやることですが、POは色んな人に助けを求めるべきだとも思います。
チームで協力して一つの製品をつくり上げるのだから、POの足りない資質は
チームメンバーが協力してあげればいいなーって。

作業を全て1人でやったらパンクするわけで、作業を割り振って
結果をAgreeするのがPOでも僕はいいんじゃないかなーって。
(これは怒られるフラグか???)

「LEARN TO UNTANGLE」:CHANGEWORLDS さん

ちぇんわさんが、タイトル間違えてる!って言ってたんで直しておきました。
解くことを学ぶ!ってことでいいのかな

ちぇんわさんの事例を元に、対立って何なの?ってことを
改めて考えさせられる発表でした。

そもそも、事例自体もちぇんわさんの遭遇して考えた結果なので
自分に当てはまらないとしても、手段の対立ってのは
タイムライン上でもよく見かける気がします。

  • この言語はいいけど、あの言語はだめだ
  • あのプロセスはいいけど、このプロセスはダメだ
  • このプロセスを使うなら、この手段を使わないといけない

言い方が否定的になればなるほど、対立が強く見える気がしました。
あと、手段だけにフォーカスがあたってしまって
「なぜ」の部分がすっ飛んでることが多いと思ってます。

ハイリスク・ハイリターン は間違えてないとおもいますが
同じ目的に向かって走っている仲間と対立したときは
リスクを誰かが背負わなくてはならない なんてことを一度忘れて
みんなで幸せになれる方法を探すと、良い解決策が見つかるかなーって思います。

最後に

しばやまさん、ちぇんわさん、素晴らしい発表をありがとうございました。
とても楽しく色々と考えることが出来ました。

次回は、いんだれさんがしゃべるらしいですねwww
日本鼻メガネの会がこんなに入り込んでいいのかという疑問もありますが
みんな楽しそうなので良しすることにします。

書きまくって消して書きまくってを繰り返したので
ぶっとんでる部分もありますが、またなんかあれば追記しようと思いますw