Search on the blog

2015年11月21日土曜日

Spockでテストする

Spcokとは?
  • テスティングフレームワーク
  • Java、Groovyのアプリケーションのテストができる
  • テストはGroovyで書く

導入方法
build.gradleに以下を追記する。
cglib:cglib-nodep:2.2というライブラリを入れておくとインターフェースを作っていないクラスの場合でもモックオブジェクトが作れて便利。

apply plugin: 'java'
+apply plugin: 'groovy'
apply plugin: 'eclipse'

repositories {
    mavenCentral()
}

dependencies {
    compile 'org.projectlombok:lombok:1.16.6'
    compile 'io.netty:netty-all:4.1.0.Beta1'
    testCompile 'junit:junit:4.12'
+    testCompile 'org.spockframework:spock-core:1.0-groovy-2.4'
+    testCompile 'cglib:cglib-nodep:2.2'
}

サンプル1
まずは簡単なやつから。
package com.kenjih.spoc;

public class FizzBuzz {
    public String calc(int x) {
        if (x % 15 == 0)
            return "Fizz Buzz";
        if (x % 3 == 0)
            return "Fizz";
        if (x % 5 == 0)
            return "Buzz";
        return String.valueOf(x);
    }
}
上のFizz Buzzをテストするコードを書いてみる。
package com.kenjih.spoc

import spock.lang.Specification;

class FizzBuzzTest extends Specification {

    def test() {
        setup:
        FizzBuzz f = new FizzBuzz()
        
        expect:
        f.calc(x) == ret
        
        where:
        x      |  ret
        3      |  "Fizz"
        10    |  "Buzz"
        15    |  "Fizz Buzz"
        0      |  "Fizz Buzz"
        101 |  "101"
    }
}

サンプル2
もうちょっと複雑なテストを書いてみる。
ServiceからDaoを呼んでいるときに、Daoの戻り値を恣意的に変えたり、Daoのメソッドが呼ばれた回数をカウントしたりできる。
package com.kenjih.spoc;

import java.util.HashMap;
import java.util.Map;

import lombok.NonNull;
import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
public class UserService {
    
    @NonNull
    final UserDao userdao;
    
    public boolean login(String uid, String pass) {
        if (uid == null || pass == null)
            return false;
        
        Map<String, Object> cond = new HashMap<String, Object>();
        cond.put("uid", uid);
        cond.put("pass", pass);
        
        return userdao.count(cond) == 1;
    }
}

メソッド名には日本語も使えて便利。。
package com.kenjih.spoc

import spock.lang.Specification;

class UserServiceTest extends Specification {
    def "uidとpassが正しい場合のみログイン成功する"() {
        setup:
        UserDao userDao = Mock()
        userDao.count(_) >> rowCount
        UserService userService = new UserService(userDao)
        
        expect:
        userService.login(uid, pass) == res

        where:
        uid       | pass      | rowCount | res 
        null      | "1234" | 1               | false
        "taro" | null        | 1               | false
        "taro" | "1234" | 0               | false
        "taro" | "1234" | 1               | true
    }
    
    def "uidかpassがnullのときはDBアクセスしない"() {
        setup:
        UserDao userDao = Mock()
        UserService userService = new UserService(userDao)
        
        when:
        userService.login(null, "abcd")
        then:
        0 * userDao.count(_)
        
        when:
        userService.login("jiro", null)
        then:
        0 * userDao.count(_)

        when:
        userService.login("yukiko", "xyz")
        then:
        1 * userDao.count(_)
    }
}

Gradleを使ってみる

 Gradleというビルドシステムを使ってみた。
groovyで書かれたツールらしい。Mavenよりも便利そうな感じ。

$ brew install gradle
$ gradle -v
$ cd ~/tmp/sample
$ gradle init --type java-library
$ ls -l
-rw-r--r--  1 kenjih  staff  1212 11 21 01:02 build.gradle
drwxr-xr-x  3 kenjih  staff   102 11 21 01:02 gradle
-rwxr-xr-x  1 kenjih  staff  4971 11 21 01:02 gradlew
-rw-r--r--  1 kenjih  staff  2404 11 21 01:02 gradlew.bat
-rw-r--r--  1 kenjih  staff   636 11 21 01:02 settings.gradle
drwxr-xr-x  4 kenjih  staff   136 11 21 01:02 src
$ find src -name '*.java'
src/main/java/Library.java
src/test/java/LibraryTest.java

initでプロジェクトの雛形を作ってくれる。
その際、gradle wrapper(gradleをインストールしていないユーザのためにgradle自体を自動でインストールしてくれるスクリプト)も自動で作ってくれる。
build.gradleの雛形も作ってくれるので、これに依存するライブラリやIDE用のpluginを追記していけばよさそう。

2015年11月17日火曜日

Pythonのdoctestが便利

 Pythonの関数のコメント部にテストを仕込めるらしい。
テストサンプルを見ると、その関数が何をするのかぱっと見で分かるので、便利。
import doctest
import operator

def aggregate_val(f, x):
    """ aggregate values of a dict "x" with a binary function "f".
    >>> aggregate_val(operator.add, {'x': 10, 'y': 20})
    30
    >>> aggregate_val(min, {'x': 10, 'y': 20})
    10
    """
    return reduce(f, [v for _, v in x.items()])
    
if __name__ == '__main__':
    doctest.testmod()

スクリプトから実行して、エラーがあると教えてくれる。

また、-vオプションを指定するとテストの詳細を教えてくれる。
kenjih$ python main.py -v
Trying:
    aggregate_val(operator.add, {'x': 10, 'y': 20})
Expecting:
    30
ok
Trying:
    aggregate_val(min, {'x': 10, 'y': 20})
Expecting:
    10
ok
1 items had no tests:
    __main__
1 items passed all tests:
   2 tests in __main__.aggregate_val
2 tests in 2 items.
2 passed and 0 failed.
Test passed.

2015年11月9日月曜日

コンテキスト用ユーティリティ

 Pythonのcontextlibというモジュールが興味深かったので、メモ。

語句の意味
「コンテキスト」という語句はプログラミングを書いてるとよく聞くが、理解が曖昧だったので調べてみた。
context managerは、リソースの割り当て、解放を必要なときに行ってくれるもの。
contextは、”状態”と考えるといい。リソースが開いている、トランザクションが実行中などの”状態”を指す。

サンプルソース
まず、contextlibを使う前に以下のソースを考える。
if __name__ == '__main__':
    with open('test.in') as f:
        for line in f:
            print line
with 句を抜けると、ファイルがcloseされるのは知っているけど、どうなってるのか?

以下のように、__enter__と__exit__を実装したクラスを作ると、with句の前後でそれぞれのメソッドが呼ばれる。これをうまく使えば、fileのopen、closeが出来そうなのが分かる。
class HogeContext:
    def __enter__(self):
        print "open context..."
    def __exit__(self, exc_type, exc_value, traceback):
        print "close context..."

if __name__ == '__main__':
    with HogeContext():
        print "hello, world"

それじゃあ、__enter__と__exit__を実装していないクラスだとwith句は使えないのか?
と思うが、それを解決するのがcontextlib。
from contextlib import closing

class Foo:
 def doit(self):
  print "do something..."
 def error(self):
  raise Exception('Foo exception...')
 def close(self):
  print "closing..."
 
if __name__ == '__main__':
 with closing(Foo()) as foo:
  foo.doit()
  foo.error()
上のようにclosing(obj)はwith句を抜けたときにobj.close()が呼ばれるようなコンテキストマネージャを返す。
でこれ何が嬉しいの?というと、
from contextlib import closing
import urllib

with closing(urllib.urlopen('http://www.python.org')) as page:
    for line in page:
        print line
のように使えて、嬉しい。

より柔軟なコンテキストの管理をしたい場合は、以下のようにデコレータを使ってコンテキストマネージャを作ることもできる。
from contextlib import contextmanager

@contextmanager
def SomeContext():
    print "begin some context..."
    try:
        yield
    finally:
        print "end some context..."

if __name__ == '__main__':
    with SomeContext():
        print "Hello, world."    
        raise Exception()

2015年11月8日日曜日

[Coursera] Game Theory Final

 Courseraのゲーム理論の期末試験を受けた。

授業のクイズ、週ごとの課題がすべて満点だったので、
期末試験も満点取ったるぞーという意気込みで、
土曜日まじめに復習(講義ノートの見直し、課題の見直し)して、日曜テストを受けた。

結果。。。

満点でしたーーヽ( ´¬`)ノ ワ~イ !!

以下履修した感想を簡単に書いておく。
  • 英語は比較的聞きやすかった(字幕なしで理解できた)
  • 一部難しい内容があった(Mixed Strategyのナッシュ均衡を求めるアルゴリズムのところ、ベイジアンゲームの定式化)が、概ね易しい内容だった
  • 内容を理解するには、大学入試〜大学1・2年くらいの数学力は必要と思われる
  • 例題が多く、抽象的な概念を理解するのを助けてくれた
  • 課題やクイズは 専門用語の定義を抑えていれば概ね解けると思われる
  • 授業の評価とは関係のないゲームがあって、それがなかなか面白かった

PostgreSQLの勉強(1)

 仕事でPostgreSQLを使うらしいので、簡単な使い方を抑えておこうと思う。

インストール
$ brew install postgresql
$ ln -sfv /usr/local/opt/postgresql/*.plist ~/Library/LaunchAgents
でインストール、ログイン時に常時起動の設定ができる。

 すぐに試したい場合は、
$ launchctl load ~/Library/LaunchAgents/homebrew.mxcl.postgresql.plist
を実行。

接続
psqlを使って接続する。psqlでは以下のコマンドが使える。

コマンド 説明
\l データベース一覧表示
\d テーブル一覧表示
\d テーブル名 テーブルの説明
\q 終了
\i ファイル名 ファイルからクエリ実行
\? ヘルプ

他にもいろいろなコマンドがあるが、ヘルプで全量を見れる。

macのUSキーボードの場合は標準の設定だとバックスラッシュが入力できなかったので、キーボード - 入力ソース - "¥"キーで入力する文字でバックスラッシュを選択しておく。

2015年11月2日月曜日

データサイエンス系ボキャブラリーまとめ

 データサイエンス系(その他もろもろ)のボキャブラリーが乏しいので、メモ書き程度に書き溜めていこうと思う。

アドホック分析
特定の目的のために実施される単発の分析。ad-hocはその場限りの、特定の目的のための、という意味。

BlueKai
あらゆるオンライン上のデータを集め、DSP/SSPなどに販売することをビジネスモデルとしたスタートアップ。DMPベンダー。2014年オラクルに買収された。

デモグラフィック
性別、年齢、職業、年収などのユーザー属性情報。
デモグラと略される。

ジオグラフィック
国、都道府県、都市などのユーザーの地理的情報。
ジオグラと略される。

サイコグラフィック
性格、嗜好、価値感などのユーザーの心理的情報。

ランディングページ
ネット上の広告やリンクをクリックしたときに表示されるページ。
略称でLP、ランペとも呼ばれる。

コンバージョン
WEBサイト上で獲得できる最終的な成果。
商品購入、会員登録、資料請求など。

CPA
Cost Per Acquisition。顧客獲得単価。
1コンバージョンあたりの広告コスト。

フィジビリティスタディ
実行可能性調査。F/S。
事業、プロジェクトが実現可能か事前に調査すること。

クリエイティブ
広告素材全般のこと。
バナー広告の画像、テキスト広告のテキスト、キャッチコピーなど。

インプレッション
広告の露出(掲載)回数のこと。

CTR
Click Through Rate。クリック率。
クリック数 / インプレッションで算出する。

MAU
Monthly Active User。
ある月に実際にサービスを利用したユーザーの数。

DAU
Daily Active User。
ある日に実際にサービスを利用したユーザーの数。

ROI
Return on Investment。
利益 / 投資額で算出。

入稿
広告主からLP、バナーなどのクリエイティブを受け取ること。

Cookie Sync
複数のドメインでクッキー情報を共有し、サイトをまたいだユーザーの特定を可能とする仕組みのこと。

Pixel Piggyback
1*1ピクセルの透過gifを使ってCookie Syncを行う技術。
 1. サイトAに、サイトBから透過gifを読むタグを設置
 2. ユーザがサイトAを訪れると、サイトBにサイトAでのユーザ情報(ID)が送られる
 3. サイトBはクッキーを発行し、発行したIDとサイトAのIDを結びつける

pixel piggybackの例:
<img alt="" src="http://xxxx/yyy.gif?uid=zzzzzzzz" height="1" width="1" />
xxxxドメイン側では、uidパラメータの取得、クッキーの発行(xxxx側のuid発行)、両方のuidの紐付けを行ったあと、空のgifを返す。

TD
Title and Description。
広告文のタイトルと説明文のこと。

CVR
Conversion Rate。
コンバージョン数 / 広告のクリック数で算出。

直帰率
1ページのみ閲覧してサイトを去った人の割合。
そのページがセッションの始まりだった場合、何割の人がすぐにセッションを終了(他サイトに移動、ブラウザを閉じるなど)しているかを表す。

離脱率
そのページがセッションの最後になった割合。
そのページのPV数のうち、そのページがセッションの最後になった割合。

UU
Unique User数。
特定の期間内にウェブサイトを訪問したユニークなユーザ数。
"ユニークな"の測定はIPアドレス、IPアドレスとUser Agentの組み合わせで行われることが多い。

LTV
Life Time Value。顧客生涯価値。
顧客ひとりが生涯で商品・サービスに支払った金額の合計値。

CRM
Customer Relationship Management。顧客関係管理。
顧客の属性、企業との接点を管理・可視化・分析し、顧客の長期的価値を最大化するマーケティング手法。

リテンション
人材領域の文脈では人材の維持・確保、マーケティング領域の文脈では既存顧客維持を意味する。

リスティング広告
検索エンジンの検索結果に連動して表示される広告のこと。

ディスプレイ広告
画像形式の広告のこと。バナー広告。

インフィード広告
SNSやキュレーションサイトなどで、フィードの間に表示される広告。ネイティブ広告の一種。

SEM
Search Engine Marketing。
具体的には、検索エンジンの表示順をあげるSEOやキーワード連動広告への広告出稿など。

コンテンツマーケティング
ブログ、ポッドキャスト、動画などのコンテンツで見込み客をサイト内に引きつけ、資料請求や商品購入を行ってもらうマーケティング手法。

エンゲージメント
親和性。
サービスの内容が、ユーザの求めているものと一致している場合、「ユーザとのエンゲージメントが高い」という。