最近のテスト事情
むかしに比べると、かなりテストが書けるようになってきたし、TDDもだんだん慣れてきた。最近テスト書いてて便利だと思ったことについてメモっておく。
スタブを使ってbefore_filterをスキップする
describe 'GET index' do context 'ログインしている場合' do before(:each) do controller.any_instances.stub(:authenticate_user).and_return(true) end it 'hogehogeなfugafugaを取得する' do get index, params assigns[:fugafuga].should be_hogehoge end end end
ログイン判定のような、リクエストをはじく処理をbefore_filter
で実装することがよくあるけど、そういうコントローラーをテストする場合、スタブが便利だということにようやく気づいた。スタブによって、メソッドの中身をごまかして好きな値を返すようにできる。だから、before_filter
をスキップしたい場合は、とにかくスタブしてtrue
を返すようにしとけばいい。skip_before_filter
でもスキップすることはできるけど、僕はスタブを使う方が好み。
FactoryGirlを使いこなす
FactoryGirl.define do factory :user do # 連番を使えばuniquenessのバリデーションにかからなくなる sequence(:name) {|n| "user #{n}" } sequence(:email) {|n| "user#{n}@example.com" } age { rand(18..30) } after(:build) do |user| # 余計なデータを作るコールバックがあればスキップできる User.skip_callback(:after, :create, :create_data) end # ネストしたfactoryで上書きできる factory :naoty do name 'naoty' email 'naoty@example.com' age 18 end # traitで属性のグループに名前をつけられる trait :resigned do resigned_at { Time.now } end end end user = FactoryGirl.create(:user) p user.name #=> "user 1" naoty = FactoryGirl.create(:naoty) p naoty.name #=> "naoty" resigned_user = FactoryGirl.create(:user, :resigned) p resigned_user.name #=> "user 2" p resigned_user.resigned_at #=> "2013-01-19 00:43:59 +0900"
factory_girl
はテスト用のデータを簡単につくるためのgem。似たようなgemは他にもあるけど、こういうgemを使うと、テストデータを作るロジックとテストコードを分離できる。なので、いろんなテストで使われるテストデータを重複なく簡単に作ることができる。
FactoryGirlでテストデータを作成するときに、よくひっかかるのがバリデーションやafter_save
などのコールバック内の余計な処理だと思う。こういう鬱陶しい処理は、FactoryGirlのコールバックを使ってスキップしてる。
trait
は特殊なデータを作る場合にすごく役に立つ。上記の例のような「退会ユーザー」をテストに使いたいときなど、特殊なデータの属性をひとまとめにしてFactoryGirl.create(:user, :resigned)
のように簡単に作成できる。
changeマッチャが便利
describe '#resign' do let(:user) { FactoryGirl.create(:user) } it 'resigned_atを更新する' do lambda { user.resign }.should change(user, :resigned?).from(false).to(true) end end
モデルの更新系のメソッドをテストするとき、change
マッチャが非常に便利。上の例で言うと、user.resigned?
の結果がlambda内の処理を実行した前後でfalse
からtrue
に変わることをテストしている。
東京Ruby会議10にいってきた
1/13, 1/14に千葉で行われた"東京"Ruby会議10にいってきた。
受付でまず渡されたのが、砂浜でMacを開く謎のバッヂ×4(後にささたつバッヂであると知らされる)。幸運にも、受付から3時間程度でバッヂをコンプし、レアバッヂをゲットできた。最初はよくわからなかったけど、楽しかった。スタッフの皆さんが楽しんでるのが伝わってきてよかった。
内容はというと、個人的にはmrubyの話がよかった。ルーターのこととかはよくわからなかったけど、組み込み機器の世界はまだまだレガシーらしく、mrubyにかかる期待は大きいみたい。"Internet of Things"的なことに興味があるので、CとかC++とかやる必要あるのかなと思ってたけど、mrubyでできるならmruby身につけたい。mrubyでつくられたスマートなルーターは実用性がありそうなデバイスでよかった。僕もmruby覚えて、一発ネタじゃない実用的なデバイスつくってみたい。mruby興味あるけど、どこから始めていいかよくわかってないので、なんとかしたい。
あとは、これまでTwitterでのみ知ってた方と初顔合わせできたのがよかった。#p4dをはじめ、コミュニティの楽しさも再確認できた。ひきつづき何かしらのコミュニティに参加したい。
2日目は大雪で途中で中断してしまったけど、スタッフの皆さんの英断のおかげで何事もなく帰宅できました。有難うございました。
Limechatのテーマつくった
昨年末から社内にIRCが導入されてから、クライアントツールにLimechatを使ってる。とりあえずデフォルトのLimelight
というテーマを使ってたけど、ビミョーに違和感があったので、自分でテーマを作ってみた。
https://github.com/naoty/Nakameguro
1時間くらいであっさりできてしまったので、そのコツをメモしておく。
cssとyamlを使う
Limechatのテーマはcssとyamlの2つで定義していく。cssはチャットのログが表示される部分(上下)のスタイルを定義するのに使い、yamlはユーザー一覧・サーバー一覧・入力部分のスタイルを定義するのに使う。これらを~/Library/Application Support/Limechat/Themes/
以下におけば、LimechatのPreferencesからテーマを設定できるようになる。
サンプルを参考にする
~/Library/Application Support/Limechat/Themes/
にSample.css
とSample.yaml
がある。これを参考に、どのクラスがどの部分にあたるのかだいたい把握できる。例えば、時間のテキストは.time
というクラスがついてるし、.sender[type=myself]
というクラスは自分のニックネームにあたる。
sassが便利
今回はcssは直接書かずにsassで書いてみた。色を多用するから、それぞれの色に変数名をつけたかった。
$ gem install sass $ sass --watch Nakameguro.sass:Nakameguro.css
とすると、Nakameguro.sass
を保存するたびにcssに変換されるため、すぐに変更を確認できる。便利。
小言
毎日使うツールは自由にカスタマイズできた方がいい。自分に合うようにカスタマイズすることで快適に開発できる。今はGUIなLimechatを使ってるけど、より柔軟にカスタマイズしたくなったらWeechatに移行するかも。
IntelliJ IDEAをvimっぽくする
Androidアプリ開発しててEclipseが重くてつらかったので、IntelliJ IDEAなるものを試してる。見た目がかっこいいからこっち使ってみようと思い、vimっぽく使えるか試してみた。
バージョン
- IntelliJ IDEA 12.0
テーマを黒にする
- こっちの方がイケてる。
Preferences > Appearance > Theme
をDarculaに変更する。
IdeaVimを追加
- キーマップをvim化する。
Preferences > Plugins > Browse repositories > IdeaVim
でダブルクリックするとインストールできる。
カーソルがどこまでも右にいける設定をオフにする
Preferences > Editor > Allow placement of caret after end of line
をオフにする。
行番号を表示する
Preferences > Editor > Appearance > Show line numbers
をオンにする。
キーマッピングをカスタマイズする
Preferences > Keymap
からいろいろ変更できる。Second Stroke
を指定することでPrefixみたいなキーマッピングも設定できる。- 変更したのは以下のとおり。これでだいたいvimと同じ動きになる。
Run
:実行Select Next Tab
,Select Previous Tab
:タブを前後に移動Recent Files
:最近開いたファイルのファイラーを起動(unite.vimっぽく使える)Split Horizontally
,Split Vertically
:エディタを水平分割、垂直分割Goto Next Splitter
,Goto Previous Splitter
:分割したエディタを前後に移動Close
:エディタを閉じる
Eclipseだとタブの移動とか画面分割をショートカットからできなかった気がするので、これだけでもインテリJ氏に替える価値があると思う。作業効率がだいぶ上がる。
2012年の振り返り・2013年の目標
KDDIの障害が復旧するのを見守るハメになったので、それまで2012年の振り返りをしようと思う。
2012年の技術面での目標は「iPhoneアプリをリリースすること」だったような気がする。これは無事に達成できた。おまけにAndroidアプリもリリースできた。あと、いくつかRailsでサービスをつくった。特にcui-about.meはなかなか好評で、海外の方にも使っていただいた。使ってもらえるサービスを作ったということも大きい成果だったと思う。覚え始めてもう2年くらいになるRailsでは、特にRSpecを書けるようになったことが一番の進歩だったと思う。まあ大半がAndroidかiOSを書いていたので、そこまで大きい進歩はなかったんだけど。最近はnode.jsをちょっとやり始めて、だんだんとわかってきたところ。Arduinoも買ってみて、ハードウェアに強い興味がでてきた。
総括すると、未知の領域にどんどんチャレンジできた年だった。
2013年の目標は「ハードウェアを開発すること」にしようと思ってる。ハードウェアといってもいろいろあるけど、とりあえず製品として売れるものを開発したい。いま一番興味があるのはハードウェアで、特にモノとモノとがインターネットにつながった未来に興味がある。Webサービスやアプリの開発自体もすごく楽しいんだけど、これまでの路線から想像がついてしまう未来ではなく、一歩先の未来を実現できるエンジニアになりたいと思う。そのために、これまでとはまったく異なる領域にチャレンジしたい気持ちが強い。2013年は2012年よりもっと大きくステップアップしたい。
HTMLも分からないまったくのド素人だった2年半前からここまで来れたという事実は今ではすごく自信になっていて、新しくチャレンジすることにポジティブになれる。今年だって、iPhoneアプリだけじゃなくAndroidアプリも作ることができて、さらに自信につながった。だから、来年もまた大きなチャレンジをしたいと思う。毎年そうやってチャレンジを繰り返して成功体験を重ねていけたら幸せだなぁと、年の瀬にしみじみ思いました。
今年お世話になった皆様、ありがとうございました。来年も宜しくお願い致します。よいお年をお迎えください。
Herokuでhubotを使ったIRC botを動かす
最近、会社でIRCブームが来てるので、僕もhubotを使ってなにかbotを作ってみることにした。hubotはGithubが作ったbotフレームワークで、TwitterのbotとかIRCのbotを簡単に作ることができる。
で、できたのがこれ。
https://github.com/naoty/diobot
ディオ(DIO)様の名言をランダムに返してくれる、最高に「ハイ!」なbotが出来上がりました。
Herokuでhubotをデプロイするときにhubotのwiki*1を参考にしてみたんだけど、Herokuにpushすると、下のようなエラーが出てぜんぜんうまくいかなかった。
Starting process with command `bin/hubot -a irc -n Hubot` Stopping all processes with SIGTERM bin/hubot: 3: npm: not found Process exited with status 0
結局、このwikiは参考にせずに自力でなんとかしたので、その記録をちゃんとメモに残しておこうと思う。
package.json
$ mkdir diobot $ cd diobot $ vi package.json { "name": "diobot", "version": "0.0.1", "author": "naoty", "description": "DIO sama at irc", "license": "MIT", "dependencies": { "hubot": "*", "hubot-scripts": "*", "optparse": "*", "hubot-irc": "*", "coffee-script": "*", "underscore": "*" }, "engines": { "node": "0.8.x", "npm": "1.1.x" } } $ npm install
dependencies
にあるパッケージは、先述のwikiに従ってたときに使ってたpackage.jsonに書いてあったのでそのまま使った。- あと、
coffee-script
はデプロイ時にエラーになったので追加した。 underscore
は便利なので、とりあえず追加した。
Procfile
$ vi Procfile bot: hubot -a irc -n DIO
- Herokuによると*2、Heroku側で
bin:node_modules/.bin:/usr/local/bin:/usr/bin:/bin
にPATHを通してくれるので、Procfileではhubot
とすればいい。 -a <Adapter名> -n <IRCのニックネーム>
をオプションにつける。
Herokuにデプロイ
$ git push heroku master ... $ heroku ps:scale bot=1 $ git config:add HUBOT_IRC_SERVER='irc.example.com' HUBOT_IRC_ROOMS='#hoge' HUBOT_IRC_NICK='DIO' HUBOT_IRC_PORT='6667' HUBOT_IRC_PASSWORD='hogehoge'
スクリプトを追加
$ mkdir scripts $ vi scripts/ping.coffee module.exports = (robot) -> robot.respond /PING$/i, (msg) -> msg.send 'PONG'
scripts/
以下にあるスクリプトは自動で読み込まれて有効になる。- これをデプロイして
dio ping
って送ったらPONG
とDIOが返したら成功。 - あとは、工夫して面白いbotを作るだけ。
Enjoy!
node.js環境構築
websocketを使ったリアルタイムなアプリケーションを作りたくなったので、node.jsを始めようと思った。とりあえず、いろいろ必要なものをインストールしたので、それをメモに残しておく。
nodebrew
$ curl https://raw.github.com/hokaccha/nodebrew/master/nodebrew | perl - setup $ vi .zprofile export PATH=$HOME/.nodebrew/current/bin:$PATH $ source .zprofile
- node.jsはバージョンがどんどん更新されるようなので、Homebrewではなくパッケージマネージャーでインストールする。
- 他にもnvmやnaveというものがあるらしいが、zshとの相性がよくないという話なので、nodebrewを選択した。
node.js & npm
$ nodebrew install stable $ nodebrew use stable $ node -v v0.8.16 $ npm -v 1.1.69
- nodebrewを使ってnode.jsとnpmをインストールする。
bower
$ npm install bower -g
- bowerはTwitter謹製のクライアントサイドのライブラリに特化したパッケージマネージャー。
- jQuery, underscore.js, bootstrapなどのリソースをpackage.jsonと同じようにプロジェクト毎にインストールできるのが便利。
- Railsだとjquery-railsなどgemのなかにそれらのリソースが含まれることもあるけど、node.jsはそういうのなさそうなので、重宝しそう。
例
例として、いま見てた本のサンプルプロジェクトで扱うリソースをbowerで管理してみる。
// component.json { "name": "fileupload", "version": "0.0.1", "main": "./public/stylesheets/style.css", "dependencies": { "jquery": "*", "jquery-ui": "*", "jquery-file-upload": "*", "jquery-masonry": "*", "fancybox": "*" } }
これでbower install
とすればインストール完了。
NoSQL
$ brew install couchdb $ mkdir -p ~/Library/LaunchAgents $ cp /usr/local/Cellar/couchdb/1.2.0/Library/LaunchDaemons/org.apache.couchdb.plist ~/Library/LaunchAgents/ $ launchctl load -w ~/Library/LaunchAgents/org.apache.couchdb.plist
追記(2012/12/22)
node.jsでbowerを使うには
$ tree -I node_modules . ├── app.js ├── package.json ├── public │ ├── component.json // <- ここに配置 │ ├── components // <- ここにインストールされる │ ├── images │ ├── javascripts │ └── stylesheets │ └── style.css ├── routes │ └── index.js └── views ├── layout.jade └── index.jade $ cd public $ bower install
bower install
でインストールされるライブラリは同じディレクトリ内のcomponentsというディレクトリに入る。なので、public内にcomponent.jsonを配置してbower install
すればよさげ。
node-dev
$ npm install node-dev -g $ node-dev app.js
node app.js
で起動すると、ファイルを変更するたびに再起動する必要がありめんどくさい。node-devを使うとその必要がなくなるので、とても便利。インストール必須だと思う。