Hatena::ブログ(Diary)

ふぃーるどのーつ@はてな

2012-12-09

JUnitテストの実行環境をバージョンアップする時の落とし穴 #tddadventjp

21:38

これはTDD Advent Calendar jp: 2012参加記事です。

前日(8日目)は、KTZさんの「Rhino.Mocksをちょっとだけ幸せにするお助けクラス」でした。

xUnitによるテスティングフレームワークの共通仕様として、「テストクラス内のテストの実行順序は不定」というのがあります。

とはいえこの仕様をテストを書く上で意識することはあまりありません。テストのあるべき姿として、テストメソッドは他のメソッドから独立しているべきですし、JUnitの場合、ほとんどの実行環境上で、ソースコード上の並びと同一順でテストが実行されていたからです。

しかしJava7(Oracle実装)からは事情が異なります。

package jp.fieldnotes.java;

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

public class OrderTest {

	@Rule
	public TestName name = new TestName();
	
	@Test
	public void インスタンスから値を取得できること() {
		System.out.println(name.getMethodName());
	}

	@Test
	public void 引数にnullを渡した時にnullが返ること() {
		System.out.println(name.getMethodName());

	}

	@Test
	public void キーが重複している場合に例外になること() throws Exception {
		System.out.println(name.getMethodName());
	}
}

上記のようなテストケースをJUnit4.10以前で実行した場合*1、java6で実行した場合は

インスタンスから値を取得できること
引数にnullを渡した時にnullが返ること
キーが重複している場合に例外になること

という順番となりますが、Java7で実行した場合は

引数にnullを渡した時にnullが返ること
インスタンスから値を取得できること
キーが重複している場合に例外になること

という結果となります。

これはJUnitがテストメソッドの一覧を取得しているのに使用している java.lang.class#getDeclaredMethods() が、Java6以前とJava7で異なった順番で結果を返すためです。この結果に引きずられて、テストの実行順序もかわってくるわけです。

前述しているように、テストメソッド相互の独立性を確保していればこの問題にひっかかることはないのですが、static領域の書き換えを行っているなどでテストメソッド同士が暗黙に依存してしまっている場合は、この問題がひっかかります。

...という問題をJUnitのメンテナも認識していたようで、JUnit4.11からはテストの実行順序に関する仕様がかわりました。

JUnit4.11からは、テストメソッドは、実行環境に関係なく、テストメソッドの名称のハッシュコードの昇順で実行されるのが仕様となりました。

もし今まで通りの順番で実行したい場合は、テストクラスに@FixMethodOrder(MethodSorters.JVM) のアノテーションを付与することにより、これまでと同じ順番で実行されます。この他にもテストメソッドの名前でソートして実行される@FixMethodOrder(MethodSorters.NAME_ASCENDING) のアノテーションが用意されています。

前述した通り、テストメソッド相互が独立しているような、あるべき姿でテストを書いていれば、この問題にひっかかることは少ないと思います。しかしながら、一定規模のテストケースがある状態で、JVMバージョンアップする場合や、JUnitバージョンアップする場合は、要注意のポイントとなるでしょう。

*1WindowsXP SP3+ Java6 u31/ Java7 u3です。Javaが古いのは作者が調査してから公開するのをサボっていたためです^^;

2012-04-27

Java7でCobertureが動かなかったら

22:23

Java7でCobetureでカバレッジ取ろうとすると、テスト走らせるところで

java.lang.VerifyError: Expecting a stackmap frame at branch target 76 in method jp.xxxxx.xx.xxx.xxxxxx.SessionData.getData(Ljava/lang/String;)Ljava/io/Serializable; at offset 27

みたいな例外吐いて落ちたりします。

こういう場合は、VMの起動オプション

<junit fork="yes" forkmode="once">
  <jvmarg value="-XX:-UseSplitVerifier" /> 

"-XX:-UseSplitVerifier"をつければいいです。(上はantの場合)

Mavenだったら

 -DargLine=-XX:-UseSplitVerifier

かなあ。試してないけど。

参考

http://vikashazrati.wordpress.com/2011/10/09/quicktip-verifyerror-with-jdk-7/

http://maven.apache.org/plugins/maven-surefire-plugin/test-mojo.html#argLine

2011-12-01

#tddbc の作り方( #TddAdventJp )

23:23

TDD Advent Calendar jp: 2011の先頭バッターであるこのエントリでは、先日開催したTDDBC横浜での経験をもとに、みなさんがTDDBCを開催することになった場合に、気をつけるといいことを書きたいと思います。

宣言

まずは「やります!」と宣言することからはじまります。TDDBCはやりたいと意思表明すれば誰でも開催することができますが、TDDBCのMLで宣言すると、開催経験のあるみなさんのサポートを受けることができてよいでしょう。

会場手配

会場を確保しないことには話がはじまりません。地域にもよりますが、首都圏の場合は半年以上前から公共施設の受付がはじまるので、早めのスタートが肝心です。また、多くの自治体では、公共施設の予約の時に使用者登録が必要となります。

会社の会議室を借りれる場合はスケジュールに余裕はでますが、稟議のフローは確実に進めてください。

基調講演の手配

必須ではありませんが、多くのTDDBCでは基調講演やTDDのデモを行っています。TDDBCのMLで協力を依頼するのがいいと思います。このフローは会場手配と並行して進めることになるので、スピードが求められます。

会場下見

会場が決まったら下見です。会場のキャパシティがわからないと受付枠が決まらず、参加受付をはじめることができないので、早めに行ってください。

TDDBCは実習形式のため、テーブルは島形式となります。このため会場のカタログ上の定員よりも実際の収容人数が減るため、この部分を確認してください。

また電源の確認も重要です。IT関係の企業に勤めていると忘れがちですが、公共施設の会議室というのは参加者が1人1台PCを持ち込むことを想定したつくりになっていません。参加者に電源コードの持参をお願いすることもできますが、それぞれの島までの配線は主催者側で確保できるようにする必要があると思います。

ネットワーク環境も重要です。無線LANが提供されていれば御の字ですが、イーモバイルWiMAX等の電波が入るか、確認しておいたほうがいいでしょう。

スタッフの手配

サポートできる言語を決めるため、サポートスタッフを募る必要があります。TDDBCのMLや、地域の技術コミュニティに協力を仰ぐのがいいと思います。私見となりますが、ポイントとなるのはPHPのサポートスタッフを確保できるかだと思います。

参加受付

イベントの申込サイトは最近雨後のたけのこ状態ですが、それぞれ特色があるので、実現できること&実現できないことがあるため、慎重に選択する必要があります。

ATND

TDDBCに限らず多くのイベントで ATNDを使用されています。OpenIDを使用してTwitterはてなgooglemixi,Yahoo!JAPAN,livedoor,Flickr,はてな のユーザアカウントで登録を行うことがため、これらのサービスの中では一番敷居は低いですが、ユーザがATNDにメールアドレスを登録していない場合に、主催者側から連絡を取ることが難しくなると言う問題があります。また、事前に参加費の徴収を行いたい場合は、AATND::Paymant等の外部サービスを使う必要があります。

この記事を書いている12/1 、現行のATNDからフォークしたイベントアテンドの開設がアナウンスされました。こちらでは事前のユーザアカウント登録が必要になり、この際にメールアドレス登録が必要になるため、主催者から確実に連絡を取る方法が確保されることになりました。また参加費の事前決済にも対応したようです。

こくちーず

ユーザ登録が必要ないため、この中では一番間口が広いといえるでしょう。ただし、イベント開設時に、メールアドレスの登録を必須にしておくことに注意する必要があります。また、参加費の事前徴収はできません。

PARTAKE

受付をTwitterアカウント所持者に絞ってもよく、かつ参加費が当日徴収でいいならPARTAKEは有力な選択肢です。ただPARTAKEは参加者への連絡を参加者自身のアカウントからダイレクトメッセージを送信することで行うのですが、一部のTwitterクライアント(夜フクロウTweetings for Twitter等)ではこのメッセージが表示されないという問題があります。

Zusaar

こちらもTwitterアカウントが必要ですが、こちらはPayPalと連携して参加費を事前に徴収することが可能です。

Doorkeeper

こちらはFacebookとの連携ができ、PayPalとの連携もできます。

connpass

私見ですが、Twitter/Facebookアカウントを連携しているのに、パスワードの登録が必要という仕様は、運営の気持ちはわかりますがイケてないです。他の特色は自分も使い込んでいるいないのでよくわからんです、ごめんなさい...

まとめると、Twitter/Facebookアカウント所持者に限定していいか、また参加費を事前徴収するかどうかが、サイト選択時のポイントになります。

また、当日写真撮影して公開する場合は、それが申込者の目に付くようにイベント開設時に考慮する必要があります。

先着順か、抽選か?

首都圏でのTDDBC開催では申込が受付枠の2倍〜3倍に達する場合があるため、受付を先着順にするか受付順にするか考える必要があります。早い者勝ちのアルティメットの方が主催側は楽なのですが、これまでの傾向を見ると、我先に申し込むためかキャンセルがかなりの数発生しているように見受けられます。抽選にはそういう問題はありませんが、抽選結果や、キャンセル繰り上がりの連絡手段を考えなければいけないため、運営側の負担は増します。

余談ですが、どうやっても開催直前のキャンセルというのは発生するので、首都圏の開催の場合は4〜5名程度の人数ずれが発生しても運営に支障がないようにしておく必要があります。と同時にこれをご覧になっているみなさんには、直前キャンセルは極力避けていただくようにご協力お願い申し上げますm(__)m

弁当

TDDBCを1日コースで開催する場合、講演、デモ、実習、コードレビューとカリキュラムを詰め込むことになります。なので、時間の有効活用として主催者側で弁当を用意して参加者間の交流やライトニングトークス等に当てる場合がありますが、ここまで書いてきたような理由で参加者数がぶれると弁当が余ってしまう場合があります。ですから、主催者がイベント開催になれてない場合は避けた方が無難です。余った弁当を持ち帰って家の家庭ゴミとして処分するのは切ないものがあります...

当日の役割分担

最低でも当日の受付を仕切る人と会場設営を仕切る人は分けてください。この2つを1人で仕切るのは無理です。また当日は主催者は色々とこなすことがあるため、タイムキーパーの役をどなたかにお願いしておいた方がいいでしょう。

領収書

領収書の発行をもとめられる場合があるので、準備しておいてください。なお、TDDBCのようなイベント参加費は消費税の課税取引となりますので、明細に消費税の金額も記載しておいた方が無難です。*1

お題

TDDBCでは、午後の実習のお題を考えるのが開催者の特権のようになっていますが、別に1人で考えなければいけないということはないです。また、これまでの課題で公開されているものもあるため、参考にするといいでしょう。

また、課題をどのように参加者に見せるかと言うことも考える必要があります。ネットワークが使用できる環境であれば、公開されているサーバアクセスして、課題を閲覧できるようにするのがいいと思います。逆にネットワーク環境が期待できないのであれば、事前にカードに印刷して参加者に配布するのがよいでしょう。

懇親会

懇親会の仕切りもできれば他の方にお願いした方がいいでしょう。でないと開催直前になって当日の準備と懇親会の人数把握などの諸々が両方降りかかってパニックになります。

さいごに

ここまで書いてきて分かるとおり、イベントを行うには色々考える必要があります。ですが、TDDBCは「やりたい」と手をあげれば始められるイベントです。自分で、イベントをつくりあげたいという意志さえあれば、それを支えてくれる方が大勢いらっしゃいますので、自分がTDDBCを「開催したい」と強く願うのであれば、勇気を出して飛び込んでみることをおすすめします。

それではTDDBCでお会いしましょう。

続いてのエントリは誕生日を迎えたかわにしさんのTDD少年です。

*1:納税が必要なわけではないです

2011-11-13

TDD Boot Camp ( #tddbc )横浜を開催しました。

23:10

11/5、TDDについての実践イベントTDD Boot Camp 横浜を開催しました。色々至らない点がございましたが、スタッフの皆様のご協力で無事終わらせることができました。当日の内容については、すでにTDD Boot Camp(TDDBC) - TDDBC横浜/記録にまとめられていますので、運営サイドからの反省点をまとめたいと思います。

抽選制度

今回新しい試みとして、抽選制度を導入しましたが、その副次的な効果として、キャンセルが減少するという効果があったみたいです。スケジュールとかをあまり調整しないで我先に申し込まれる方が減少したためでしょうか。(当日受付でドタキャンに見えたのは前日にキャンセルの連絡を受けていたのを、私が受付用名簿に反映できていなかったものです。)ただ、抽選制度を導入した場合はこくちーずとかATNDとかpartakeとかのキャンセル機能が事実上使えなくなるため、繰り上がりの連絡を個別に行わなければいけないことになり、運営側の負担は増すと思います。

後今回は会場キャパシティに対する受付枠をギリギリのところで設定していたので、前日キャンセルはできれば勘弁して欲しかったです。余裕があればそこらへんをみこして受付枠にバッファをつくれたんですが...

ちなみに、抽選はこくちーずからCSVダウンロードして、そいつをrubyスクリプトに喰わせて当選・キャンセル待ちに仕分けるという方法をとりました。ATNDとかでもシフトJISで申込者CSVダウンロードできれば使えると思います。

準備

事前の打ち合わせはskypeで個別に行っていましたが、自分だけしか握っていない情報が発生してしまったので、グループチャットとかlingrとかで情報共有できるようにしたほうがよかったですね。SCMBCはlingrを活用しているみたいですし。

設営

そして当日ですが、最低でも会場設営を仕切る人と受付を仕切れる人は分けておくべきでした。この両方を一人で仕切るのは無理です、はい。そしてid:yujioramaには色々がんばってもらったのですが、ネットワーク環境が不調だったのは申し訳ないと思います。ただ、横浜市内で参加者にネットワーク環境を提供できて終日借りることができる施設となると、パシフィコ横浜とかになってしまうんですよw。そうすると参加費が4,000円とかになってしまうので、もし次回やるとしたら参加者の方のイーモバイルとかWiMAXとかは接続できるロケーションにはしたいと思います。

ペアプロ・コードレビュー

ペアプロとコードレビューですが、当初3イテレーションを予定していましたが、実際には2イテレーションしか実施できませんでした。最初のコードレビューの時にタイムキープが機能しなかったのが原因で、申し訳ないです。(ネットワークの不調に対応していたため)。もっと実際に手を動かす時間がほしいと思われた参加者もいらっしゃったと思うんですが、これ以上はデモとか講演の時間をやりくりして捻出するしかないので、1日のカリキュラムとしては難しいところですね。

課題

課題なんですが、出題者の趣味丸出しの課題設定(野球の打率計算)にもかかわらずみなさま意欲的に取り組まれたようで、それは喜ばしく思っています。ただ、私が最初にそもそもの野球の打率とはなんぞやという説明をすっ飛ばすという失態を犯しましたm(__)mドメインに特化した課題を出す場合は、この点の考慮は絶対必要ですね。

あと、急遽追加したデモのところでid:t-wadaが四捨五入を実装するところから学習テストの説明にもっていったところは、さすが和田さんだと思いました。(出題者はそこまで考えていませんでした...)

おわりに

色々反省点はありましたが、やってみて、次やるならこうしたいという点も見えてきたので、もしよろしければもう1回チャンスをいただければと思います。あと、yokohama.rbのみなさまには全面的に協力をいただきました。どうもありがとうございました

11/14追記

電源問題に先行きが見えない段階で会場下見につきあって色々助言いただいたid:nobeansにも盛大な拍手を!

他、id:t-wadaをはじめとして色々支えていただいたみなさま、本当にありがとうございました。

2010-09-22

地道に便利なEclipse 3.6のデバッガ機能拡張〜例外ブレークポイントのサブクラス指定

00:30

Eclipseデバッガには例外をスローしたときにブレークする例外ブレークポイントという機能があり、例外発生時のオブジェクトの状態を詳しく見たい場合などは重宝します。ただ例外のクラスそのものずばりを指定する必要があり、JDBCのようにインターフェースで規定した例外のサブクラスが飛ぶ場合や、「例外が発生した場合は全てブレーク」のような使い方ができないため、かゆいところに手がとどかない感がありました。

しかしEclipse3.6から例外ブレークポイントに"Subclasses of this exception"というオプションが加わり、指定した例外のサブクラスの例外が発生したときにブレークすることができるようになりました。

f:id:setoazusa:20100923002730p:image

画像ではjava.lang.RuntimeExceptionのそのサブクラスブレークポイントをはっていますが、ぬるぽでブレークしてているのがおわかりいただけると思います。

f:id:setoazusa:20100923002731p:image

まあ、例外メッセージにしっかり情報を含めるようにしてあれば、本来このような手間は不要なんですが。