ヘッド有りブラウザーで動きみたいときもある。

$ brew install chromedriver
# test/test_helper.rb:
Capybara.register_driver :chrome do |app|
  Capybara::Selenium::Driver.new(app, :browser => :chrome)
end

Capybara.javascript_driver = :chrome

ヘッドレスブラウザとか言ってらんない人用。

selenium

% sudo su
% mkdir /usr/lib/selenium/
% cd /usr/lib/selenium/
% wget http://selenium.googlecode.com/files/selenium-server-standalone-2.25.0.jar
% mkdir -p /var/log/selenium/
% chmod a+w /var/log/selenium/

seleniumのinit scriptを書く。

% sudo vi /etc/init.d/selenium
#!/bin/bash

case "${1:-''}" in
    'start')
        if test -f /tmp/selenium.pid
        then
            echo "Selenium is already running."
        else
            export DISPLAY=:99
            java -jar /usr/lib/selenium/selenium-server-standalone-2.25.0.jar > /var/log/selenium/selenium-output.log 2> /var/log/selenium/selenium-error.log & echo $! > /tmp/selenium.pid
            echo "Starting Selenium..."

            error=$?
            if test $error -gt 0
            then
                echo "${bon}Error $error! Couldn't start Selenium!${boff}"
            fi
        fi
    ;;
    'stop')
        if test -f /tmp/selenium.pid
        then
            echo "Stopping Selenium..."
            PID=`cat /tmp/selenium.pid`
            kill -3 $PID
            if kill -9 $PID ;
                then
                    sleep 2
                    test -f /tmp/selenium.pid && rm -f /tmp/selenium.pid
                else
                    echo "Selenium could not be stopped..."
                fi
        else
            echo "Selenium is not running."
        fi
        ;;
    'restart')
        if test -f /tmp/selenium.pid
        then
            kill -HUP `cat /tmp/selenium.pid`
            test -f /tmp/selenium.pid && rm -f /tmp/selenium.pid
            sleep 1
            export DISPLAY=:99
            java -jar /usr/lib/selenium/selenium-server-standalone-2.25.0.jar > /var/log/selenium/selenium-output.log 2> /var/log/selenium/selenium-error.log & echo $! > /tmp/selenium.pid
            echo "Reload Selenium..."
        else
            echo "Selenium isn't running..."
        fi
        ;;
    *)      # no parameter specified
        echo "Usage: $SELF start|stop|restart|reload|force-reload|status"
        exit 1
    ;;
esac
% sudo chmod 755 /etc/init.d/selenium
% sudo update-rc.d selenium defaults

xvfbとfirefox(iceweasel)

% apt-get install xvfb iceweasel

xvfbのinit scriptを書く。

% sudo vi /etc/init.d/xvfb
#!/bin/bash

XVFB=/usr/bin/Xvfb
# XVFBARGS=":99 -fbdir /var/run -ac"
XVFBARGS=":99 -nolisten tcp -fbdir /var/run"
PIDFILE=/var/run/xvfb.pid
case "$1" in
  start)
    echo -n "Starting virtual X frame buffer: Xvfb"
    start-stop-daemon --start --quiet --pidfile $PIDFILE --make-pidfile --background --exec $XVFB -- $XVFBARGS
    echo "."
    ;;
  stop)
    echo -n "Stopping virtual X frame buffer: Xvfb"
    start-stop-daemon --stop --quiet --pidfile $PIDFILE
    echo "."
    ;;
  restart)
    $0 stop
    $0 start
    ;;
  *)
        echo "Usage: /etc/init.d/xvfb {start|stop|restart}"
        exit 1
esac

exit 0
% sudo chmod a+x xvfb
% update-rc.d xvfb defaults

Migrations Pluginの導入

cakeディレクトリがcake_core/cakeという感じで置かれていて色々設定しないとcakeコマンドが動かないのでデフォルトの位置に戻した。おそらくcakeコマンドによるgenerateは使ってなかったんだろう。generateを使わないとCakePHPのレールから大幅に外れることになりがち。cakeコマンドが動いたことによってようやくmigrations pluginを導入できた。現状のDBの状態をmigrationファイルに変換できたが、そもそも初期データはどうあるべきなのかがわからないので困った。テーブルが50ぐらいあるDBの初期データを手で作っていたら日が暮れてしまう。相談したところ、初期化に使っているSQLがあるとのことでそれを頂いた。とても助かった。

一番手っ取り早いテスト

seleniumでテストを書いている。とにかく「このページ開いたらエラーが出てるんですけど」という状態を無くしたい。capybaraとかであれば「GETしてステータス200かどうかだけを調べる」というのを量産すれば可能だけどseleniumでステータスが取れるかどうかがわからない。そもそもPHPでWARNINGとかが発生した時ってHTTP的には普通に200をかえしちゃったりしてないだろうか?試してみよう…。(どなたか知ってる方がいたら教えていただけるとありがたいです)

hrysd苦戦

@hrysdは引き続きバグ修正。数日前にPHPはじめたのに頑張っている。しかし元々ソースがカオスなので一箇所修正したと思ったら、その影響で他のどこかが壊れるということが多発する。一刻も早く自動テストを増やさねば。

コメントを入れる

バグ修正をしているとき、下記の用な感じで変数名やカラム名が全然意味がわからないのでわかったところにコメントを入れてた。変数名や関数名を分かりやすくしてあればこんな作業は必要無いのに…。カラム名のD1, SD, MT, YDとかまったくわからない。なぜカラム名の長さの数バイトをケチるのにsessionにバカでかいデータを入れまくるのか。

$dd = $tk[0]['NcrmDTeiki']['D1']; // 発生日付(YYYYMMDD)
$dd = $tk[0]['NcrmDTeiki']['SD']; // 配送予定期間(開始日付)(YYYYMMDD)
if ( $tk[0]['NcrmDTeiki']['MT'] == 3 ) {
    if ( $tk[0]['NcrmDTeiki']['SD'] > 0 ) {
        $dd = $tk[0]['NcrmDTeiki']['SD'];
    }
}
$kyou = date('Ymd');
$kyou = $chd[0]['NcrmDCyuumon']['D1'];
if ( $lst != 0 ) { $kyou = $lst; }
// 次の日付を求める
$yyy = substr($dd,0,4);
$mmm = substr($dd,4,2);
$ddd = substr($dd,6,2);
if ( $mmm == 4 or $mmm == 6 or $mmm == 9 or $mmm == 11 ) {
    if ( $ddd == 31 ) {
        $ddd = 30;
    }
}
if ( $mmm == 2 ) {
    if ( $ddd >= 29 ) {
        $ddd = 28;
    }
}
if ( $tk[0]['NcrmDTeiki']['MT'] == 1 ) {
    $mmm = $mmm + 0; if ( $mmm == 13 ) { $yyy = $yyy + 1; $mmm = 1; }
    $ddd =$tk[0]['NcrmDTeiki']['YD'];
}
(この1行目と2行目は同じ変数に連続して代入してるので明らかにおかしいと思うんだが、怖いので触れない)

プログラマーを探す

このブログでも募集文を書いているが、社長も開発会社を探してくれている。目安として、"作業担当者のGithubアカウントもしくは見せられるコードがあること"を条件に探しているんだが、今までの5〜6社で該当するところが一つもない。普通そういうもんなんだろうか。下記のようにGithubでPHPのrepos持ってて、Tokyo在住の人のブログとかをみて、開発を受け付けているか探したほうが早いんじゃないかと思った。

Search · location:tokyo

定期購入機能が間に合わない問題

ECのシステムで定期購入という機能がある。一回買うと定期的にものが送られてくる機能だ。この機能の実装がバグが多発(というかまだできてない)していて困っている。

実装的にちょっとバグが出ているなら直せばいいんだけど、仕様の段階で破綻しているっぽいので悩む。

定期購入を実現するために今の仕様では、購入した時点で普通の商品と同じように1回目の伝票を1個作成するのだが、定期購入は期間をしていして、2回目、3回目、4回目などの未来の伝票を画面から手動で生成するようになっている。

伝票は編集したり削除したりできるので2, 3, 4回目が出来た後で1回目(元伝票と呼んでいる)を変更するとおかしな自体が多発する。2回目だけを消したら3回目は本当に3回目なのか?とか、2回目を消した後で次の伝票を作成(5回目を作成したいつもり)するとまた2回目が出来たり3回目が2個出来たり…。

そもそも手動で伝票を生成するのなら定期購入って意味あるのか?というのはあるにしろ、定期購入というのは実物の伝票ではなく、購入に関するルールという抽象的な概念なので、実物の伝票として未来まで作成してしまう(DBにデータを作成してしまう)とルールの変更があった時に不整合がいかにも起こりやすいことはさらっと聞いただけでわかる。

今のシステム(新CRM)の前身である旧CRMはそういった不安な仕様はなく、定期購入は先に未来の伝票を何回目まで先にデータを作るといったことは無い。

開発チームの文化

締め切りが迫っている中、現状をなんとか改善するのか、仕様を見直すのか、リスケするのか、答えが出ていない。現状を改修しようとしても何らかのトラブルが起きそうなことは目に見えている。それを是とするのか非とするのか、当然非なんですが、答えのでない長時間の会議に僕も疲れてしまってとりあえず現状維持みたいな感じになってしまいました。

そういうのを是とすると、中長期的には、開発チームとして論理的矛盾やバグがあってもいい・仕方無いみたいな雰囲気が根付いてしまう。根付いた文化を変えるのはとても大変なので急に「次のバージョンからは安定したシステムを作ろう!」といってもそういった下地ができていなければ無理。まずその辺の認識を変えていかなければ…。

関連:レガシーPHP改善日記シリーズ

$ brew install selenium-server-standalone
$ cp "/usr/local/Cellar/selenium-server-standalone/2.25.0/homebrew.mxcl.selenium-server-standalone.plist" ~/Library/LaunchAgents/
launchctl load -w ~/Library/LaunchAgents/homebrew.mxcl.selenium-server-standalone.plist

便利な時代になったもんですね。(結構メモリ食うのでウザくなったら起動しない設定に変えといたほうがよさそう)

Selenium RCをインストール

PHPUnitをインストール

PHPUnit_Seleniumをインストール。

% pear install phpunit/PHPUnit_Selenium

testを書く(ファイル名はクラスと同じCamelCase)

test/integrations/LoginTest.php

<?php
require_once 'PHPUnit/Extensions/SeleniumTestCase.php';

class LoginTest extends PHPUnit_Extensions_SeleniumTestCase
{
    protected function setUp()
    {
        $this->setBrowser('*firefox');
        $this->setBrowserUrl('http://foo/');
    }

    public function testTitle()
    {
        $this->open('/sign_in');
        $this->assertTitle('Sign In');
        $this->type('account', 'foo');
        $this->type('password', 'password');
        $this->submitAndWait('user_form');
        $this->assertTitle('Dashboard');
    }
}
?>

実行。対象ディレクトリ以下のなんとかTest.phpを全部実行する。

$ phpunit test/integrations