Codeceptionを使ってみた(2) Unitテスト

前回は Codeceptionを使ってみた(1) - think it over

簡単なCLIアプリケーションをテストしてみようと思います。
前回の予告どおり、題材はFizzBuzz問題を取り上げてみます。

今回はFizzBuzzを生成する箇所のUnitテストを書いています。

1. テスト対象の作成

プロジェクトのルートにsrcディレクトリを作成し、その中にFizzBuzzを生成するクラスを実装します。

<?php
namespace DevMStudy\Tdd;

class FizzBuzz
{
    public function generate($start, $end)
    {
        $fizzBuzz = [];
        for ($i = $start; $i <= $end; $i++) {
            if ($i % 15 === 0) {
                $fizzBuzz[] = "FizzBuzz";
            } else if ($i % 3 === 0) {
                $fizzBuzz[] = "Fizz";
            } else if ($i % 5 === 0) {
                $fizzBuzz[] = "Buzz";
            } else {
                $fizzBuzz[] = $i;
            }
        }
        return $fizzBuzz;
    }
}

名前空間は適当に。コードの良し悪しはさておき。。。

2. Unitテストの作成

2.1. テストを生成

FizzBuzzが正しくgenerateされるかどうかをテストするために、unitテストを作成します。
Codeceptionではテストを作成する際には、generateコマンドを利用します。

generate
  generate:cept            Generates empty Cept file in suite
  generate:cest            Generates empty Cest file in suite
  generate:phpunit         Generates empty PHPUnit test without Codeception additions
  generate:scenarios       Generates text representation for all scenarios
  generate:suite           Generates new test suite
  generate:test            Generates empty unit test file in suite

これらです。

generate:testを使います。

C:\workspace\proj> .\vendor\bin\codecept.bat generate:test unit "DevMStudy/Tdd/FizzBuzz"
Test was created in C:\workspace\proj\tests\unit\DevMStudy\Tdd\FizzBuzzTest.php

生成されたFizzBuzzTest.phpを見ると、

  • _before
  • _after
  • testMe

の3つのメソッドが存在します。
このクラス、最終的には「PHPUnit_Framework_TestCase」を継承しており、「_before」「_after」はそれぞれPHPUnitの「setUp」「tearDown」の中で呼ばれるようになっています。

2.2. テストを記述

「testMe」をそれらしい名前に変えてテストを書いていきます。

<?php
    public function testGenerateFizzBuzzSucceed()
    {
        $I = $this->codeGuy;
        $target = new FizzBuzz();
        $fizzBuzz = $target->generate(1, 30);

        $I->expect("count(\$fizzBuzz) is 30");
        $this->assertCount(30, $fizzBuzz);

        $I->expect("1 is 1");
        $this->assertEquals(1, $fizzBuzz[0]);

        (以下略)
    }

PHPUnit_Framework_TestCase」を継承しているので、assertEqualsとか使えます。
「$I->expect」はコードおよびテストの結果出力の可読性向上のためのもので、テストの挙動には影響のないものです。

2.3. テストを実行

runコマンドでテストを実行できます。
いろいろオプションはあります。

C:\workspace\proj>vendor\bin\codecept.bat run unit --steps
Codeception PHP Testing Framework v1.6.3.1
Powered by PHPUnit 3.7.21 by Sebastian Bergmann.

Suite unit started
Trying to test generate fizz buzz succeed (DevMStudy\Tdd\FizzBuzzTest::testGenerateFizzBuzzSucceed)
* I expect count($fizzBuzz) is 30
* I expect 1 is 1
* I expect 2 is 2
* I expect 3 is Fizz
* I expect 5 is Buzz
* I expect 6 is Fizz
* I expect 10 is Buzz
* I expect 15 is FizzBuzz
* I expect 16 is 16
* I expect 30 is FizzBuzz
 - Ok


Time: 0 seconds, Memory: 4.75Mb

OK (1 test, 10 assertions)

以上です。次回はコンソール出力のテストを書いてみます。

Codeceptionを使ってみた(1) 導入

個人的に大注目しているPHP用のテスティングフレームワーク

Codeception - BDD-style PHP testing.

を試しています。
まだ日本語情報が少ないですが、以下のコードを見て一発で気に入ってしまいました。

<?php 
$I->am('testing framework');
$I->wantToTest('your web application');
$I->see('it works!');

Codeceptionってなに?

特徴としては、

といったところでしょうか。

2013/7/8時点の最新バージョンは1.6.3.1、活発に開発も行われています。

このエントリからではCodeceptionの導入編として、

  • インストール&起動方法
  • 基本的なテストの書き方

を紹介してみます。

たぶん長くなるので、適当に分割します。

0. 前提情報

1. インストール

基本的には Quick Start Codeception を参照すればOKと思いますが、私はComposerを利用しました。

1.1. Composerの取得

Composer に倣って。

C:\workspace\proj> php -r "eval('?>'.file_get_contents('https://getcomposer.org/installer'));"
#!/usr/bin/env php
All settings correct for using Composer
Downloading...

Composer successfully installed to: C:\workspace\composer.phar
Use it: php composer.phar

1.2. Composerでプロジェクトを初期化

C:\workspace\proj> php .\composer.phar init

1.3. Codeceptionを依存関係に追加

C:\workspace\proj> php .\composer.phar require --dev codeception/codeception 1.6.*

vendorディレクトリ配下に依存パッケージが追加されます。
また、cliコマンドはvender/binディレクトリにインストールされます。
Codeceptionは「内部ではPHPUnitを利用」している、と書いたとおり、
vendor/bin配下には

の両方のCLIコマンドがあることがわかります。

1.4. 動作確認

C:\workspace\proj> vendor\bin\codecept.bat

として、バージョン番号やUsageが表示されればOKです。

2. テストの初期化

C:\workspace\proj>vendor\bin\codecept.bat bootstrap

Initializing Codeception in C:\workspace\proj

File codeception.yml created <- global configuration
tests/unit created <- unit tests
tests/functional created <- functional tests
tests/acceptance created <- acceptance tests
tests/unit.suite.yml written <- unit tests suite configuration
tests/functional.suite.yml written <- functional tests suite configuration
tests/acceptance.suite.yml written <- acceptance tests suite configuration
Building initial Guy classes
Building Guy classes for suites: acceptance, functional, unit
WebGuy includes modules: PhpBrowser, WebHelper
WebGuy.php generated successfully. 45 methods added
TestGuy includes modules: Filesystem, TestHelper
TestGuy.php generated successfully. 11 methods added
CodeGuy includes modules: CodeHelper
CodeGuy.php generated successfully. 0 methods added

Bootstrap is done. Check out C:\workspace\proj/tests directory

プロジェクトのルート配下に

  • codeception.yml
  • testsディレクトリ

が作成されます。

さらにtestsディレクトリ配下には

  • acceptance(受入テスト)
  • functional(機能テスト)
  • unit(単体テスト

のそれぞれのYML設定ファイルおよびテストを格納するディレクトリ、またログ出力ディレクトリ等が作成されます。
ちなみに、Codeceptionでは「acceptance」や「functional」など、を「test suite」と呼び、任意のtest suiteを作成することも可能です。
参考:Codeception Commands

Guyって?

上の出力で、

  • WebGuy
  • TestGuy
  • CodeGuy

というものがありますが、これは、

One of the main concepts of Codeception is representation of tests as actions of a person. We call this person a Guy.

http://codeception.com/docs/02-GettingStarted

だ、そうです。
BDDの特徴の一つとして、より「自然言語に近い」形でテストを記述する、というものがありますが、これを支えているのが「Guy」達なんですね。
実際には「Guy」に「$I」という変数名を与えることで

$I->wantTo("test web application");

みたいなコードを記述することが可能となります。


いったん、以上です。
次回FizzBuzz問題を題材にテストを書いてみます。

Gitのワークフロー・運用ルールを決める上で参考になるサイトたち

Symfony2プロジェクトをGitLabで管理してVagrantで立てたJenkinsでCIする(番外)

番外編です。

Jenkinsのチャートの文字化けを修正する

チャートの日本語がいわゆる「豆腐」状態になってしまっていると思います。

を参考にし、修正します。

もちろん、Vagrant + Chef-Soloでやります。
イテレーション C: JenkinsをVagrantで構築する で作成したJenkinsのcookbookのレシピに以下を追加します。

yum_package "vlgothic-fonts" do
  action :install
end

directory "/usr/lib/jvm/jdk1.7.0_21/jre/lib/fonts/fallback" do
  owner "root"
  group "root"
  mode 0755
  action :create
end

link "/usr/lib/jvm/jdk1.7.0_21/jre/lib/fonts/fallback/VL-Gothic-Regular.ttf" do
  filename = "/usr/share/fonts/vlgothic/VL-Gothic-Regular.ttf"
  to filename
  not_if {
    ::File.symlink?('/usr/lib/jvm/jdk1.7.0_21/jre/lib/fonts/fallback/VL-Gothic-Regular.ttf') &&
    ::File.readlink('/usr/lib/jvm/jdk1.7.0_21/jre/lib/fonts/fallback/VL-Gothic-Regular.ttf') == filename
  }
end

vlgothicをyumでインストールして、fonts/fallback配下にシンボリックリンクを作成しています。

これで、Jenkinsを再起動すれば、文字化けは解消されます。
f:id:piccagliani:20130523144240p:plain

以上です。

Symfony2プロジェクトをGitLabで管理してVagrantで立てたJenkinsでCIする(6)

第6回です。

前回のおさらい
イテレーション D: JenkinsでCIする
Jenkinでプロジェクトをビルドできるようになりました。

今回の内容
PHPMDやPHPCS等の各種ツールを導入し、Jenkinsと連携してみます。


いまどこ?

  1. イテレーション 0: 準備
    1. タスク 0-1: 必要なソフトウェアをインストールする
    2. タスク 0-2: GitLabのアカウントを作成する
  2. イテレーション A: Symfony2でプロジェクトをはじめる
    1. タスク A-1: Symfony2プロジェクトを作成する
    2. タスク A-2: GitLabでソースコードを管理する
    3. タスク A-3: PHPUnitを導入する
  3. イテレーション B: Phingでプロジェクトをビルドする
    1. タスク B-1: Phingを導入する
    2. タスク B-2: PhingとPHPUnitを連携する
  4. イテレーション C: JenkinsをVagrantで構築する
    1. タスク C-1: VMを初期化する
    2. タスク C-2: 構築に必要なCookbooksを取得・作成する
    3. タスク C-3: Jenkinsを起動する
  5. イテレーション D: JenkinsでCIする
    1. タスク D-1: Jenkinsにプロジェクトを設定する
    2. タスク D-2: テストレポートを表示できるように設定する
    3. タスク D-3: コードカバレッジレポートを表示できるように設定する
  6. イテレーション E: 各種ツールの導入 ←いまココ!
    1. タスク E-1 PHPMDを導入する
    2. タスク E-2 PHPCSを導入する


イテレーション E: 各種ツールの導入

タスク E-1 PHPMDを導入する

  • 依存関係の追加
C:\workspace\Symfony2>php composer.phar require --dev phpmd/phpmd dev-master
composer.json has been updated
Loading composer repositories with package information
(中略)
Installing assets using the hard copy option
Installing assets for Symfony\Bundle\FrameworkBundle into web/bundles/framework
Installing assets for Acme\DemoBundle into web/bundles/acmedemo
Installing assets for Sensio\Bundle\DistributionBundle into web/bundles/sensiodistribution

  • 単体で実行
C:\workspace\Symfony2>bin\phpmd src xml cleancode
<?xml version="1.0" encoding="UTF-8" ?>
<pmd version="@package_version@" timestamp="2013-05-22T19:12:09+09:00">

(中略)

    <violation beginline="59" endline="59" rule="StaticAccess" ruleset="Clean Code Rules" externalInfoUrl="http://phpmd.org/rules/design.html#staticaccess" priority="1">
      Avoid using static access to class '\ReflectionClass' in method 'getControllerCode'.
    </violation>
  </file>
</pmd>

  • Phingから実行

Phingでプロジェクトをビルドする でも登場した素晴らしい Gist を参考にbuild.xmlを修正します。
不親切で申し訳ないですが、全文載せると長いので、変更点のみを。

@@ -15,9 +15,14 @@

     <!-- Default target -->
     <target name="build:main"
-            depends="build:clean, build:prepare, build:test"
+            depends="build:clean, build:prepare, build:check, build:test"
             description="Run all test and build everything" />

+    <!-- Check target -->
+    <target name="build:check"
+          depends="check:md"
+          description="Analyzes app code." />
+
     <!-- Test target -->
     <target name="build:test"
             depends="test:unit"
@@ -46,4 +51,13 @@
             --coverage-html   ${dir.reports.coverage}/
             -c ${dir.app}"/>
     </target>
+
+    <!-- Mess detector -->
+    <target name="check:md" description="Generate code metrics.">
+        <echo msg="Generating code metrics ..." />
+        <phpmd rulesets="cleancode,codesize,unusedcode">
+            <fileset refid="sourcecode" />
+            <formatter type="xml" outfile="${dir.reports}/pmd.xml" />
+        </phpmd>
+    </target>
 </project>
\ No newline at end of file

編集を保存したら実行します。

C:\workspace\Symfony2>bin\phing -logger phing.listener.DefaultLogger check:md
Buildfile: C:\workspace\Symfony2\build.xml

Symfony2 > check:md:

     [echo] Generating code metrics ...
    [phpmd] Processing files...
    [phpmd] Finished processing files

BUILD FINISHED

Total time: 3.3765 seconds

「C:\workspace\Symfony2\build\logs\pmd.xml」が生成されていることが確認できたら、
ここまでの変更内容をコミットして、GitLabに反映しておきます。

  • Jenkinsと連携

プラグインマネージャから「PMD Plugin」をインストールします。
その後は前回と同様に、「プロジェクト設定」から「「ビルド後の処理」の追加をします。
f:id:piccagliani:20130522145943p:plain

設定変更を保存したらビルドします。

ビルドが完了すると、プロジェクトトップに「PMD警告」というリンクが新たに表示されますので、クリックして以下の画面が表示されればOKです。
f:id:piccagliani:20130522151139p:plain

タスク E-2 PHPCSを導入する

大きな流れはPHPMDと同様となります。

  • 依存関係の追加

packagistに
squizlabs/php_codesniffer - Packagist
があるのですが、バージョン番号が正常に表示されなかったりと、なんかアヤシイので、PEAR提供のものを利用します。
【php】PEARをインストールする(Composerで) at softelメモを参考にさせていただきました。

PEARライブラリをcomposerで利用可能とするために、composer.jsonを以下のように編集します。

@@ -4,6 +4,12 @@
     "autoload": {
         "psr-0": { "": "src/" }
     },
+    "repositories": [
+        {
+            "type": "pear",
+            "url": "http://pear.php.net/"
+        }
+    ],
     "require": {
         "php": ">=5.3.3",
         "symfony/symfony": "2.2.*",
@@ -47,6 +53,7 @@
     },

そして、いつものrequireです。

C:\workspace\Symfony2>php composer.phar require --dev pear-pear.php.net/PHP_CodeSniffer 1.4.*

  • 単体で実行

何も指摘されないと面白くないので、
src\Acme\DemoBundle\Controller\DemoController.php をイケてない状態にします。

@@ -10,14 +10,12 @@ use Acme\DemoBundle\Form\ContactType;
 use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
 use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;

-class DemoController extends Controller
-{
+class DemoController extends Controller {
     /**
      * @Route("/", name="_demo")
      * @Template()
      */
-    public function indexAction()
-    {
+    public function indexAction() {
         return array();
     }

PSR2でチェックします。

C:\workspace\Symfony2>bin\phpcs -s -w --standard=PSR2 src

FILE: C:\workspace\Symfony2\src\Acme\DemoBundle\Controller\DemoController.php
--------------------------------------------------------------------------------
FOUND 2 ERROR(S) AFFECTING 2 LINE(S)
--------------------------------------------------------------------------------
 13 | ERROR | Opening brace of a class must be on the line after the definition
    |       | (PSR2.Classes.ClassDeclaration.OpenBraceNewLine)
 18 | ERROR | Opening brace should be on a new line
    |       | (Squiz.Functions.MultiLineFunctionDeclaration.BraceOnSameLine)
--------------------------------------------------------------------------------


FILE: ...workspace\Symfony2\src\Acme\DemoBundle\Twig\Extension\DemoExtension.php
--------------------------------------------------------------------------------
FOUND 0 ERROR(S) AND 2 WARNING(S) AFFECTING 2 LINE(S)
--------------------------------------------------------------------------------
 36 | WARNING | Line exceeds 120 characters; contains 147 characters
    |         | (Generic.Files.LineLength.TooLong)
 64 | WARNING | Line exceeds 120 characters; contains 146 characters
    |         | (Generic.Files.LineLength.TooLong)
--------------------------------------------------------------------------------

Time: 0 seconds, Memory: 2.50Mb

イケてない状態がちゃんと指摘されています。

  • Phingから実行

build.xmlを編集します。
おなじみ素晴らしい Gist のとおり、「phpcodesniffer」タスクを利用すると、

PhpCodeSnifferTask requires PHP_CodeSniffer version >= 1.2.2

と怒られた(phpcsコマンドが見つからない??)ので(なぜphpmdは大丈夫なの?)「exec」タスクを使います。

@@ -20,7 +20,7 @@

     <!-- Check target -->
     <target name="build:check"
-          depends="check:md"
+          depends="check:md, check:cs"
           description="Analyzes app code." />

     <!-- Test target -->
@@ -60,4 +60,16 @@
             <formatter type="xml" outfile="${dir.reports}/pmd.xml" />
         </phpmd>
     </target>
+
+    <!-- code sniffer -->
+    <target name="check:cs" description="Checks coding standard.">
+        <echo msg="Checking coding standard ..." />
+        <exec command="${dir.bin}/phpcs
+            -s -w
+            --standard=PSR2
+            --report=checkstyle
+            --report-checkstyle=${dir.reports}/checkstyle.xml
+            ${dir.src}
+            "/>
+    </target>
 </project>

Jenkinsとの連携のため、レポートを「checkstyle」形式にしています。

実行してみます。

C:\workspace\Symfony2>bin\phing -logger phing.listener.DefaultLogger check:cs
Buildfile: C:\workspace\Symfony2\build.xml

Symfony2 > check:cs:

     [echo] Checking coding standard ...

BUILD FINISHED

Total time: 0.7612 seconds

「C:\workspace\Symfony2\build\logs\checkstyle.xml」が生成されていることが確認できたら、
ここまでの変更内容をコミットして、GitLabに反映しておきます。

  • Jenkinsと連携

プラグインマネージャから「Checkstyle Plugin」をインストールします。
「プロジェクト設定」から「「ビルド後の処理」の追加をします。
f:id:piccagliani:20130522193117p:plain

設定変更を保存したらビルドします。

ビルドが完了すると、プロジェクトトップに「Checkstyle警告」というリンクが新たに表示されますので、クリックして以下の画面が表示されればOKです。
f:id:piccagliani:20130522193416p:plain

最後に

phpmd, phpcs以外のツールたちも、上のような手順でJenkinsと連携できるはずです。
機会があれば別個のエントリとして書いてみようと思います。


以上です。

Symfony2プロジェクトをGitLabで管理してVagrantで立てたJenkinsでCIする(5)

第5回です。

前回のおさらい
イテレーション C: JenkinsをVagrantで構築する
世に公開されているcookbooksをかき集めてJenkinsを立ち上げました。

今回の内容
いよいよプロジェクトをJenkinsに設定し、CIしてみます。


いまどこ?

  1. イテレーション 0: 準備
    1. タスク 0-1: 必要なソフトウェアをインストールする
    2. タスク 0-2: GitLabのアカウントを作成する
  2. イテレーション A: Symfony2でプロジェクトをはじめる
    1. タスク A-1: Symfony2プロジェクトを作成する
    2. タスク A-2: GitLabでソースコードを管理する
    3. タスク A-3: PHPUnitを導入する
  3. イテレーション B: Phingでプロジェクトをビルドする
    1. タスク B-1: Phingを導入する
    2. タスク B-2: PhingとPHPUnitを連携する
  4. イテレーション C: JenkinsをVagrantで構築する
    1. タスク C-1: VMを初期化する
    2. タスク C-2: 構築に必要なCookbooksを取得・作成する
    3. タスク C-3: Jenkinsを起動する
  5. イテレーション D: JenkinsでCIする ←いまココ!
    1. タスク D-1: Jenkinsにプロジェクトを設定する
    2. タスク D-2: テストレポートを表示できるように設定する
    3. タスク D-3: コードカバレッジレポートを表示できるように設定する
  6. イテレーション E: 各種ツールの導入
    1. タスク E-1 PHPMDを導入する
    2. タスク E-2 PHPCSを導入する


イテレーション D: JenkinsでCIする

タスク D-1: Jenkinsにプロジェクトを設定する

  • Gitプラグインのインストール

GitLabからプロジェクトの変更を取得するためにJenkinsがGitを扱えるようにならないといけません。
そのためのプラグインをアップデートセンターからインストールします。
http://192.168.33.10:8080/pluginManager/available にアクセスし、右上の「フィルター」から「Git Plugin」で検索すると、

Git Plugin
   This plugin allows use of Git as a build SCM. Git 1.3.3 or newer is required.

が表示されるので、チェックします。「ダウンロードして再起動後にインストール」をぽちり。
「プラグインのインストール/アップグレード」画面が表示されるので、「インストール完了後、ジョブがなければJenkinsを再起動する」にチェックし、しばし、待ちます。

  • GitLabにDeploy Keyを設定する

GitLabからプロジェクトの変更を取得するためのもうひとつの作業として、Jenkins実行ユーザーのSSH公開鍵をGitLabに追加する必要があります。
Jenkinsサーバー上での作業が必要となりますが、jenkinsユーザーのデフォルトshellが「/bin/false」になっているため、まずはそこを有効にします。

C:\Users\{$user}\VirtualBox VMs\centos> vagrant ssh
Last login: Tue May 21 21:30:14 2013 from 10.0.2.2
Welcome to your Vagrant-built virtual machine.
[vagrant@localhost ~]$ sudo vi /etc/passwd

jenkins:x:497:498:Jenkins Continuous Build server:/var/lib/jenkins:/bin/false

最後の「/bin/false」を「/bin/bash」に変更します。

ssh-keygenします。パスフレーズは空にしてます。

[vagrant@localhost ~]$ sudo su - jenkins
-bash-4.1$ ssh-keygen -t rsa -C "jenkins@localhost"
Generating public/private rsa key pair.
Enter file in which to save the key (/var/lib/jenkins/.ssh/id_rsa):
Created directory '/var/lib/jenkins/.ssh'.
Enter passphrase (empty for no passphrase):
Enter same passphrase again:

「~/.ssh/id_rsa.pub」の内容を

https://gitlab.com/{$user_name}/symfony2/deploy_keys/new

から登録します。

一度接続を行い、GitLabのホスト公開鍵をknown_hostsに追加しておきます。

-bash-4.1$ git ls-remote -h git@gitlab.com:{$user_name}/symfony2.git HEAD
The authenticity of host 'gitlab.com (54.243.197.170)' can't be established.
RSA key fingerprint is b6:03:0e:39:97:9e:d0:e7:24:ce:a3:77:3e:01:42:09.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'gitlab.com,54.243.197.170' (RSA) to the list of known hosts.

これをしておかないと、次の「ジョブの作成」で以下のエラーに苦しめられます。

Failed to connect to repository : Command "git ls-remote -h git@gitlab.com:{$user_name}/symfony2.git HEAD" returned status code 128:
stdout:
stderr: Host key verification failed.
fatal: The remote end hung up unexpectedly

  • ジョブの作成

プロジェクトをビルドするためのジョブを新規に作成します。
http://192.168.33.10:8080/newJob にアクセス。
「ジョブ名」に「Symfony2」を入力、「フリースタイル・プロジェクトのビルド」にチェックし、「OK」ボタンを押します。
f:id:piccagliani:20130521125504p:plain

ジョブの設定画面に進みますので、「ソースコード管理」と「ビルド」の箇所を設定します。

ソースコード管理」の設定
Gitを選択し、リポジトリのURLを入力します。
f:id:piccagliani:20130521132219p:plain

「ビルド」の設定
「ビルド手順の追加」から「シェルの実行」を選択し、以下の内容を記入します。

/usr/local/bin/composer install --dev
bin/phing

f:id:piccagliani:20130521134901p:plain

もはや説明は不要だと思いますが、ここでやっていることは以下の2つです。。

  1. Composerで依存関係をインストール
  2. Phingでビルド

これでビルド出来る状態になりましたので、「保存」ボタンを押して設定変更を反映します。

  • ビルドしてみる!

設定変更が完了すると「プロジェクト Symfony2」画面に遷移するので、右のナビゲーションから「ビルド実行」をクリックします。
しばらくしたら、http://192.168.33.10:8080/job/Symfony2/1/console にてコンソール出力を確認します。
どきどきしながら待ちます。
f:id:piccagliani:20130521135655p:plain
初回のビルドでは依存関係のインストールが行われるので、結構な時間がかかります。

最終的に、コンソールに以下のような出力がされれば、ビルド成功です。

BUILD FINISHED

Total time: 14.4189 seconds
[m
Finished: SUCCESS

http://192.168.33.10:8080/job/Symfony2/ws/build/logs/coverage/index.html
にアクセスして、カバレッジレポートが出力されていることも確認します。


ここまでですでにお腹いっぱいですが、もうちょっと続きます。

タスク D-2: テストレポートを表示できるように設定する

Symfony2ジョブの設定画面にアクセスします。
http://192.168.33.10:8080/job/Symfony2/configure

「ビルド後の処理」から「JUnitテスト結果の集計」を選択します。
「テスト結果XML」に

build/logs/phpunit.xml

を入力します。
f:id:piccagliani:20130521142327p:plain

変更を保存し、再度ビルドします。
ビルド後、プロジェクトのトップ画面に「テスト結果の推移」が表示されれば成功です。
(ただし、2回目以降に表示されます)
f:id:piccagliani:20130521143344p:plain

タスク D-3: コードカバレッジレポートを表示できるように設定する

プラグインマネージャから、「Clover PHP plugin」をインストールします。
インストールが完了したら、Symfony2ジョブの設定画面にアクセスします。
http://192.168.33.10:8080/job/Symfony2/configure

「ビルド後の処理」から「Clover PHP カバレッジレポートを集計」を選択し、以下のように設定します。
f:id:piccagliani:20130521143704p:plain

変更を保存し、再度ビルドします。

ビルド後、プロジェクトのトップ画面に「Clover HTMLレポート」が表示されれば成功です。
f:id:piccagliani:20130521143941p:plain

最後に

「CIする」とか書いておきながら、この段階ではまだ「CI」の「Continuous」が実現できていません。
GitLabへのpushをトリガーにビルドを実行するように設定する必要があります。
そのあたりはもうちょっと後で(調査中・・・)。。。。


以上です。

第6回はイテレーション E: 各種ツールの導入

Symfony2プロジェクトをGitLabで管理してVagrantで立てたJenkinsでCIする(4)

第4回です。

前回のおさらい
イテレーション B: Phingでプロジェクトをビルドする
Phingビルドツールを導入し、PHPUnitをPhingから実行できるようになりました。

今回の内容
Vagrantを利用してJenkinsを構築します。


いまどこ?

  1. イテレーション 0: 準備
    1. タスク 0-1: 必要なソフトウェアをインストールする
    2. タスク 0-2: GitLabのアカウントを作成する
  2. イテレーション A: Symfony2でプロジェクトをはじめる
    1. タスク A-1: Symfony2プロジェクトを作成する
    2. タスク A-2: GitLabでソースコードを管理する
    3. タスク A-3: PHPUnitを導入する
  3. イテレーション B: Phingでプロジェクトをビルドする
    1. タスク B-1: Phingを導入する
    2. タスク B-2: PhingとPHPUnitを連携する
  4. イテレーション C: JenkinsをVagrantで構築する ←いまココ!
    1. タスク C-1: VMを初期化する
    2. タスク C-2: 構築に必要なCookbooksを取得・作成する
    3. タスク C-3: Jenkinsを起動する
  5. イテレーション D: JenkinsでCIする
    1. タスク D-1: Jenkinsにプロジェクトを設定する
    2. タスク D-2: テストレポートを表示できるように設定する
    3. タスク D-3: コードカバレッジレポートを表示できるように設定する
  6. イテレーション E: 各種ツールの導入
    1. タスク E-1 PHPMDを導入する
    2. タスク E-2 PHPCSを導入する


イテレーション C: JenkinsをVagrantで構築する

の繰り返しも含みますが、1から書いていきます。

タスク C-1: VMを初期化する

  • 準備

作業用ディレクトリを作ります。(以降、見やすさのためにプロンプト部分は一部省略します。)

C:\Users\{$user}\VirtualBox VMs>mkdir centos

  • boxの追加、VMの初期化
\centos>vagrant box add centos http://developer.nrel.gov/downloads/vagrant-boxes/CentOS-6.4-x86_64-v20130309.box
[vagrant] Downloading with Vagrant::Downloaders::HTTP...
[vagrant] Downloading box: http://developer.nrel.gov/downloads/vagrant-boxes/CentOS-6.4-x86_64-v20130309.box
[vagrant] Extracting box...91722240 / 491722240)[vagrant]
[vagrant] Verifying box...
[vagrant] Cleaning up downloaded box...

\centos>vagrant init centos
A `Vagrantfile` has been placed in this directory. You are now
ready to `vagrant up` your first virtual environment! Please read
the comments in the Vagrantfile as well as documentation on
`vagrantup.com` for more information on using Vagrant.

タスク C-2: 構築に必要なCookbooksを取得・作成する

  • cookbook格納用ディレクトリの作成
\centos>mkdir cookbooks

\centos>cd cookbooks
\centos\cookbooks>git clone https://github.com/opscode-cookbooks/yum
\centos\cookbooks>git clone https://github.com/opscode-cookbooks/php
\centos\cookbooks>git clone https://github.com/opscode-cookbooks/mysql
\centos\cookbooks>git clone https://github.com/opscode-cookbooks/openssl
\centos\cookbooks>git clone https://github.com/opscode-cookbooks/xml
\centos\cookbooks>git clone https://github.com/opscode-cookbooks/java
\centos\cookbooks>git clone https://github.com/opscode-cookbooks/windows
\centos\cookbooks>git clone https://github.com/opscode-cookbooks/chef_handler
\centos\cookbooks>git clone https://github.com/opscode-cookbooks/git
\centos\cookbooks>git clone https://github.com/opscode-cookbooks/build-essential
\centos\cookbooks>git clone https://github.com/opscode-cookbooks/dmg
\centos\cookbooks>git clone https://github.com/opscode-cookbooks/runit
\centos\cookbooks>git clone https://github.com/binarymarbles/chef-timezone timezone
\centos\cookbooks>git clone https://github.com/zircote/chef-composer composer

今回はphpサードパーティのものを利用します。
mysqlやらopensslやら一見関係のなさそうに見えるものもありますが、依存関係の都合で必要です。

  • オレオレcookbookを作成

Jenkinsのみ「これだ!」というサードパーティのものがなかったので、オレオレです。

\centos\cookbooks>knife cookbook create jenkins -o .

C:\Users\{$user}\VirtualBox VMs\centos\cookbooks\jenkins\recipes\default.rb を以下の内容にします。

yum_key "RPM-GPG-KEY-jenkins" do
  url "http://pkg.jenkins-ci.org/redhat/jenkins-ci.org.key"
  action :add
end

remote_file "/etc/yum.repos.d/jenkins.repo" do
  source "http://pkg.jenkins-ci.org/redhat/jenkins.repo"
  mode 0644
  action :create_if_missing
end

yum_package "jenkins" do
  action :install
end

タスク C-3: Jenkinsを起動する

  • Vagrantfileを編集する

C:\Users\{$user}\VirtualBox VMs\centos\Vagrantfile を編集します。
編集箇所は以下の2か所です。

ネットワーク設定

config.vm.network :hostonly, "192.168.33.10"

ホストオンリーにします。

Chef-Soloによるプロビジョニング

  config.vm.provision :chef_solo do |chef|
    chef.cookbooks_path = "./cookbooks"
    chef.add_recipe "timezone"
    chef.add_recipe "yum::ius"
    chef.add_recipe "php"
    chef.add_recipe "composer"
    chef.add_recipe "java"
    chef.add_recipe "jenkins"
    chef.add_recipe "git"

    # You may also specify custom JSON attributes:
    chef.json = {
      :timezone => {
        :area => "Asia",
        :zone => "Tokyo"
      },
      :yum => {
        :ius_release => "1.0-11"
      },
      :php => {
        :install_method => "package",
        :packages => %w(php54 php54-mbstring php54-pdo php54-xml php54-pecl-xdebug),
        :directives => {
          "date.timezone" => "Asia/Tokyo"
        }
      },
      :composer => {
        :install_path => "/usr/local/bin"
      },
      :java => {
        :install_flavor => "oracle",
        :jdk_version => 7,
        :oracle => {
          :accept_oracle_download_terms => true
        }
      }
    }
  end

  • VMを起動する
C:\Users\{$user}\VirtualBox VMs\centos>vagrant up
[default] Importing base box 'centos'...
[default] Matching MAC address for NAT networking...
(中略)
[2013-05-21T21:24:14+09:00] INFO: Processing package[git] action install (git::default line 31)
[2013-05-21T21:24:14+09:00] INFO: Chef Run complete in 91.731508737 seconds
[2013-05-21T21:24:14+09:00] INFO: Running report handlers
[2013-05-21T21:24:14+09:00] INFO: Report handlers complete

結構、時間かかります。

  • Jenkinsを起動する

SSHでログイン

C:\Users\{$user}\VirtualBox VMs\centos>vagrant ssh
Last login: Tue May 21 21:24:33 2013 from 10.0.2.2
Welcome to your Vagrant-built virtual machine.


Firewallを停止

[vagrant@localhost ~]$ sudo service iptables stop
iptables: Flushing firewall rules:                         [  OK  ]
iptables: Setting chains to policy ACCEPT: filter          [  OK  ]
iptables: Unloading modules:                               [  OK  ]
[vagrant@localhost ~]$ sudo service ip6tables stop
ip6tables: Flushing firewall rules:                        [  OK  ]
ip6tables: Setting chains to policy ACCEPT: filter         [  OK  ]
ip6tables: Unloading modules:                              [  OK  ]

本来はきっちり設定した方がよいと思います。

起動

[vagrant@localhost ~]$ sudo service jenkins start
Starting Jenkins                                           [  OK  ]


ブラウザから確認
http://192.168.33.10:8080/ に接続し、以下が表示されればOKです。
f:id:piccagliani:20130521112457p:plain


以上です。

第5回はJenkinsでCIする