assaulter's diary

主にバイクについて

JenkinsでiOSプロジェクトのメトリクスを測定+GHUnitの実行

前回の続きです。Jenkinsは導入済み。ちょっとだけ面倒だったのでメモしておきます。

環境

XCode - 4.5.2

ローカルプロジェクトを対象とする(Githubからpullしてきてーはまた今度)

Jenkinsにプラグインを入れる

今回必要なプラグインは下記の2つ

  1. XCode integration
  2. Jenkins CppNCSS plugin

正直XCode integrationはなくても動きますが・・・

ビルド設定

Jenkinsのプロジェクト設定画面で、ビルド手順を追加 - XCodeを選択。

f:id:assaulter:20130213114520p:plain

こんな感じに設定する。

複雑度の測定結果を出力する

参考:D.O.R.Y. : Dory Offers a Room for You - http://saturday-dory-fever.blogspot.jp

  1.  このスクリプトを実行して、複雑度の測定結果をxmlファイルとして出力するシェルを追加する。
  2. ビルド後の処理で、"publish Cpp NCSS Report"を追加する。

CppNCSS xml report pattern に、1.で作成したxmlファイルを指定する。あとは適当。

GHUnitをJenkinsから実行する

参考:guide_command_line Document - http://gabriel.github.com/gh-unit/docs/appledoc_include/guide_command_line.html

GHUnitのコマンドライン実行について - http://tech-gym.com/2011/09/objective-c/494.html

上記を参考に、GHUnitをコマンドラインから実行できるようにしておく。

Jenkinsの設定

下の画像を参考に(今回はローカルを対象に動かしてるので、そのように設定する)

f:id:assaulter:20130213114236p:plain

この状態でビルド実行すると、GHUnitが実行され、テストに通らなかった場合にはエラーになります。

Jenkinsを導入するよ

環境

Mac OSX 10.8.2

homebrew インストール済みであること

手順

brew install jenkins

いやー入れるだけなら超Easyですね。

起動方法:インストール途中に出てくるコマンドを打つだけ

java -jar /usr/local/Cellar/jenkins/1.484/libexec/jenkins.war

次回はJenkinsを使ってiOSプロジェクトのCI環境を整えるところを書きます。もうできてるんだけどね。

iOSでデリゲートメソッドを書いてみる

仕様

  1. viewでボタンを押すと通信開始
  2. 通信を行う(今回は特にデータの取得は行わない)
  3. 通信が完了したらviewのラベルを変更する

シーケンス図

f:id:assaulter:20130112181809p:plain

 MyUrlConnectionクラスが通信を行なって、通信完了イベントを受け取るのですが、ラベル変更はViewの仕事なので、デリゲートメソッドという形で委譲します。

MyUrlConnectionクラス(一部)

MyUrlConnection.h

#import 
// 通信完了したらやってほしいことがあるけど、実装はそっちまかせ
@protocol MyUrlConnectionDelegate 
-(void)didFinishedLoad;
@end

@interface MyUrlConnection : NSObject

- (void)startConnection;
@property (nonatomic,weak) id delegate;

@end

MyUrlConnection.m

// データを全て受け取ると呼び出される
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    [self.delegate didFinishedLoad];
    NSLog(@"didFinishLoading");
}

UIViewControllerクラス(一部)

Step1.h

#import 
#import "MyUrlConnection.h"

@interface Step1 : UIViewController

@property (nonatomic, weak) IBOutlet UILabel* label;
- (IBAction)clickButton:(UIButton*)sender;
@end

Step1.m(一部)

// ボタンがクリックされたらここ
- (IBAction)clickButton:(UIButton*)sender {
    [urlConect startConnection];
}

// 通信終了のお知らせ(MyUrlConnectionのデリゲートメソッド)
-(void)didFinishedLoad {
    // labelのテキストを変更する
    self.label.text = @"did finished load";
}

こうやるとdelegateを実装している誰かに対して仕事を投げつけることができるわけですね。わかります。

参考資料

Objective-Cのdelegateの機能を理解する

(メモ)GHUnitを導入する

参考その1:http://tech-gym.com/2011/08/objective-c/481.html

参考その2:http://alpha.mixi.co.jp/2012/10858/

上記の補足として、Testフォルダ内のmain.mを下記のようにする。

#import <UIKit/UIKit.h>
#import <GHUnitIOS/GHUnitIOSViewController.h>

int main(int argc, char *argv[])
{
    @autoreleasepool {
    	int retVal;
		if(getenv("GHUNIT_CLI")) {
			retVal = [GHTestRunner run];
		} else {
			retVal = UIApplicationMain(argc, argv, nil, @"GHUnitIOSAppDelegate");
		}
	}
}

追記

CACurrentMediaTime()が定義されてない!って怒られたので、ライブラリにQuartzCore.frameworkを追加しましょう。

Xcodeで単体テストを行う

Java to Objective-Cな今日この頃、コンテキストになかなかついていけず、頭堅いなぁと悩む日々です。

今日の話題はObjective-Cなコードをテストするにはどうするの?です。

単体テストをSenTestCaseで書く

別段iOSプロジェクトでなくても良かったんですが、軽くネットを徘徊した程度ではコレしか見つからなかったので、iOSなプロジェクトを作ってそこにObjective-Cのコードを書いてそれをテストすることをゴールとします。

テスト入りのプロジェクトを作る

 Xcode - NewProject - iOS Application - EmptyApplication

とすすめると"include Unit Tests"にチェックを入れる画面が出るのでそれにチェック。

f:id:assaulter:20121215155743p:plain

※プライバシー保護のために色を塗っております

f:id:assaulter:20121215155849p:plain

こんなかんじでテストファイルもできる。楽ちん!

テストを実行する

f:id:assaulter:20121215160023p:plain

デフォルトでSchemeにテストも設定されているのでCommand + Uでテストが実行されます。お疲れ様でした〜

追記

SenTestCaseはSTAssertほげほげでアサート文を書くことができる。

(オブジェクト指向修行シリーズ2)委譲メソッドのテストってどうやるんだ???

最近集約して委譲する厨になってきたassaulterです。ども。

こういう感じの委譲メソッドを実装した場合のテストってどうやるんだろうとふと思ったのですが、ぐぐっても良い感じの記事が出てこないのでどういうところで悩んでいるかを載せてみた。

自己解決したので追記しました。

public class Hoge {

    private HogeHoge hogeHoge;
	
	public Hoge() {
		this.hogeHoge = new HogeHoge();
	}
	/** コンポジでもっているクラスHogeHogeのフィールドに副作用を与えるメソッド */
	public void add(int y) { 
		hogeHoge.add(y);
	}
}

パターン1

このソースのaddメソッドは、HogeHogeクラスのフィールドに副作用を与えるメソッドなので、テストして確認するためにはこんな感じか

public class HogeTest {

    @Test
	public void test_add_1() {
		Hoge hoge = new Hoge();
		hoge.add(y);
		// ↓private で持ってるのでアクセスできない!
//		int actual = hoge.hogeHoge
//		assertEqual("テストできぬぅ!", expected, actual);
	}
}

アクセスできねーっす!テストできねーっすよ!

今回はこういう感じで逃げた

Strategyパターンっぽく書かれたコードならテストできる・・・

public class Hoge {

    private HogeHoge hogeHoge;
    
	public Hoge() {
		this.hogeHoge = new HogeHoge();
	}
    /** まさかの再代入 */
    public setHogeHoge(HogeHoge hogehoge) {
        this.hogeHoge = hogehoge;
    }
    
	/** コンポジでもっているクラスHogeHogeのフィールドに副作用を与えるメソッド */
	public void add(int y) { 
		hogeHoge.add(y);
	}
}

これどうなんすかねー?こうするとsetHogeHogeをつかってモックを入れることができるので導通テストはできます。んで、HogeHogeクラスのテストでaddメソッドの動作は保証すると。テストのためにカプセル化が壊れるのは本末転倒なのですが、多分設計が悪いんだろうなーと。

事故解決しますた

コンポジで持ってるクラスに副作用のある仕事をさせる場合、必ず外に結果が出るはずなので、それを見れば十分ですね。。。

求めるな!命じよ!(オブジェクト指向修行シリーズ)

なんとなくシリーズ化。

「求めるな、命じよ」とは?

オブジェクト指向プログラミングの原則のひとつ(らしい)

参考 : http://d.hatena.ne.jp/asakichy/20090505/1241476035

"呼び出す側が、呼び出されるオブジェクトの状態に基づいて判断して、呼び出される側のオブジェクトの状態を変更すべきではない。"

なる・・・ほど・・・?で、具体的にどうやるの?

"この原則の具体的な実現方法は「コマンドとクエリの分離原則@オブジェクト指向入門」を適用する事である。"

コマンドとクエリの・・・?

参考その2 : http://www.ogis-ri.co.jp/otc/hiroba/technical/OOADwithApplyingUMLandPatterns/index.html

「コマンド・問い合わせの分離原則」というのは、以下の観点でメソッドを設計するというものです。

コマンドメソッド
更新などの機能を実行するメソッド。 オブジェクトの状態が変更されるような効果を持ち、戻り値の型を void とする。

問い合わせメソッド
単にデータを返すだけの機能を持つメソッド。 オブジェクトの状態が変更されるような、あらゆる副作用も許さない。

なるほど。確かに、メソッドってこの2つに分類できるかも。

意識してインタフェース書いてみようっと。