AnsibleでGitlab構築(nginx MariaDB CentOS7)

かなり久しぶりの記事投稿です。最近はWindowsよりLinuxを使うことが多くその中でインフラ周りも自分で構築することも多くなりました。今回は社内開発サーバーにGitサーバーを構築するため GitLabを入れることとなりそのための手順のまとめです。 最近のGitLabではOmnibus PackageというAllInOneパッケージがありインストールはかなり楽なのですが他のサーバーと共存させるような場合には(今回はRedmine,usvn)もう少し細かいインストールができると良いなと思いました。

また今回はサーバーの構築手順を再利用するためAnsibleを使って手順を書いてみました。 以前のエントリーではChefを構築に使う記事も書いたのですが、Ansibleの場合は対象サーバーに特別に入れるソフトはいらずSSHで接続できれば良いため汎用性が高いのではないかと思います。

Ansible ソースコード

https://github.com/euledge/ansible-role-gitlab_centos7

変数でサブディレクトリでの運用やリバースプロキシに対応できるようにしています。 詳細は上記のサイトをご覧ください。

対象サーバーGitLab動作環境

CentOS7 (vagrant + virtualbox, VMWare ESXiで確認)

対象サーバーOSに事前に設定しておくもの

SELINUX

別のAnsibleのロールで以下のようにしています。

# SELINUX
- name: Install libselinux-python
  yum: name=libselinux-python state=present
- name: disabled selinux
  selinux: state=disabled
- name: Disable selinux
  selinux: policy=targeted state=disabled

rootユーザー SSH公開鍵認証の準備

対象サーバにSSH公開鍵認証方式でrootユーザーがログイン出来るように準備してください。

yumで対象サーバーに事前に入れておくもの

実行後にインストールされるもの

構築時にハマったこと

cloneしたGitLabにGemfileがあり bundle install する手順があるのですが、依存するgemが不足していましたので Gemfile.localに

gem 'charlock_holmes', '0.6.9.4'
gem 'execjs'

を追加してbundleするようにしました。 併せてexecjsが必要とする nodejs と npm をyumで事前にインストールしています。

参考にしたサイト

GitLabをCentOS7にインストールしてみた by @supertaihei02 on @Qiita http://qiita.com/supertaihei02/items/8c7b12b406cb6a1517a2 Ansibleで作るGitlab+Redmine by @volanja on @Qiita http://qiita.com/volanja/items/8362beb5a929a07afee4 GitLab Community Edition Installation from source https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/install/installation.md

WindowsでChefの環境をお手軽に入れてみたよ

前回記事Chocolateyを使用してお手軽にvagrantの環境を作成しましたが、 途中chefの環境でエラーとなってしまいあたふたしてしまいました。

今回は、そのあと調査の結果Chocolateyでお手軽にchef環境を作成するところをまとめます。

Chefといっても実際に作成するのはknife-soloの環境ををWindows側に作成するのが今回の目的になります。

knife-soloをインストールするためには、rubysshrsyncが必要になります。

まず rubyのインストールですが、ここに落とし穴がありました。 前回のお手本通り

C:\Users\xxx> cinst ruby
C:\Users\xxx> cinst ruby.devkit
C:\Users\xxx> cgem knife-solo

としたのですが、いざknifeを動かそうと思ったら、 cannot load such file -- yajl/2.0/yajl (LoadError) というエラーになってしまいます。 同じような現象に遭遇した方の記事を見てみるとどうもRuby2.0との相性が良くないみたいです。 実際にインストールされているrubyのバージョンを確認すると確かに Ruby2.0がインストールされていました。 対処方法はあるようなのですが、おとなしくRuby1.93をインストールして解決しようとしました。

C:\Users\xxx> chocolatey list ruby

で検索してみましたが、ruby 単独でv1.93のものはなく

....
ruby 2.0.0.24700
ruby.devkit 4.5.2.20111230
ruby.devkit.ruby193 4.52
....

近いものだと上記のようなものになっていました。 試しに

C:\Users\xxx> cinst ruby.devkit.ruby193

としたところ一緒にruby193もインストールできましたのでこれで進めます。

rsyncですが 前回のお手本通り

C:\Users\xxx> cinst cwrsync

とすると7z.exeが見つからない旨のエラーとなりインストールできませんでした。 ですので一旦

C:\Users\xxx> chocolatey uninstall cwrsync
C:\Users\xxx> cinst 7zip

とします。しかしどうも7zipは自動的にパスが通らないみたいなので手動で環境変数のPATHに追加してあげて

C:\Users\xxx> cinst cwrsync

で無事インストールができました。後で必要になるsshも一緒に入るようです。

グダグダになりましたがお手軽にwindowsにchef環境入れるには

C:\Users\xxx> cinst ruby.devkit.ruby193
C:\Users\xxx> cinst 7zip
ここで7z.exeの実行パスを環境変数に追加 (私の環境では C:\Program Files\7-Zip)
C:\Users\xxx> cinst cwrsync
C:\Users\xxx> cgem knife-solo

これでOK。(2013/8/27現在)

ただ、他の開発用に他のバージョンのrubyが複数あったりするとknifeうまく動かないみたいです。

Windows 8でvagrantの環境をお手軽に作ってみた

開発マシンが新しくなったのでWindows 8でvagrantの環境を作ったまとめを見ながら Windowsにvagrantとchefの環境を作成してみたが、若干記事の内容と違ってた箇所があったのでその時のメモです。

新しくPC買い替えたりするといろんなツールを再インストールしなければならないのですが、その度に配布サイトをググって検索してダウンロードして実行とか 面倒くさいことが多いんですよね。

最初はvagrantをwindowsd環境に入れようと思ってググっていたら、見つかったのが上記の記事で思わぬオマケに遭遇してしまいました。

今回インストールに使ったのはchocolatey参考にさせてもらったいくつかのサイトにも書いてあるように 要はLinuxならyumやapt-get、Macならhomebrewのようなものでとっても便利なパッケージ管理ソフトです。

以下に紹介記事があります。

chocolatey自体のインストールも簡単だし、これは使えると思います。 公開されているパッケージも様々で、公式ページにはギャラリーがありますので探してみてください。

インストールは、以下の用にコマンドラインから一発で、勝手にダウンロード元見つけて落としてくれますし、環境変数のPATHまでちゃんと通してくれます。 f:id:kuroyanagi_h:20130823132350p:plain

ちなみにギャラリーには、こんなものまでありましたが... 何が入ってくるのか確認は誰かにお任せします。 f:id:kuroyanagi_h:20130823132745p:plain

前置きはこの辺で本題に入ります。

先頭の記事では f:id:kuroyanagi_h:20130823133146p:plain のようなコマンドでOKとなっていましたが、その通りにやってみたところ cinst cwrsynでパッケージが見つからないとのエラーになりました。

先ほどのギャラリー検索したところ単なるタイポで cinst cwrsync が正しいようです。既に記事への編集リクエストがあったので、打ち直して先に進みます。

次に、cinst ruby.devkit でダウンロードした後に7zが無いとのエラーになりました。ダウンロードしたファイルの解凍に使うようなのですがそれがないとのこと

chocolateyでインストールされたパッケージのフォルダ C:/Chocolatey/bin を見てみると 7za.batはあるものの7z.batがありませんでしたので 7za.batをコピーして7z.batを同じフォルダに置いたところ無事インストールできました。

ここに記載した内容はvagrant実行に関係するものではありませんでした。その後のchefに関するものでしたのでいったん取り消しします。vagrant実行には

C:/Users/xxx> cinst virtualbox
C:/Users/xxx> cinst vagrant

のみで実行できます。(既にvirtualbox入っている方はもちろんvirtualboxのインストは不要です)

早速vagrantでubuntu-server入れてみます。 とりあえず、最小限の確認にしたかったので、

C:/Users/xxx> vagrant box add lucid64 http://files.vagrantup.com/lucid64.box
C:/Users/xxx> vagrant init lucid64

vagrant upすると

C:/Users/xxx>  vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
[default] Importing base box 'lucid64'...
[default] Matching MAC address for NAT networking...
[default] Setting the name of the VM...
[default] Clearing any previously set forwarded ports...
[default] Creating shared folders metadata...
[default] Clearing any previously set network interfaces...
[default] Preparing network interfaces based on configuration...
[default] Forwarding ports...
[default] -- 22 => 2222 (adapter 1)
[default] Booting VM...
[default] Waiting for VM to boot. This can take a few minutes.
[default] VM booted and ready for use!
[default] Mounting shared folders...
[default] -- /vagrant

vagrant sshで接続すると

C:/Users/xxx> vagrant ssh
Linux lucid64 2.6.32-38-server #83-Ubuntu SMP Wed Jan 4 11:26:59 UTC 2012 x86_64 GNU/Linux
Ubuntu 10.04.4 LTS

Welcome to the Ubuntu Server!
 * Documentation:  http://www.ubuntu.com/server/doc
New release 'precise' available.
Run 'do-release-upgrade' to upgrade to it.

Welcome to your Vagrant-built virtual machine.
Last login: Tue Aug 27 03:19:18 2013 from 10.0.2.2
vagrant@lucid64:~$

このように無事接続完了

ちなみに、タイトルにはWindows8でとありますが、PowerShellが入っていればchocolateyは使えますのでWindows7でも同じです。

chefの環境作成については次回とします。

チーム開発のための .NET 開発環境の整備(DBマイグレーション)

.NETでのチーム開発のための環境整備を社内で作成しているところですが、備忘もかねて作業記録や気が付いた点など書いていきます。


今回はデータベースのMigrationについて記載します。

今回の概要

  1. Migrationでスキーマの履歴を管理する

今回の環境

  • VisualStudio 2012
  • Entity Framework 5.0
  • ASP.NET MVC4

1. Migrationでスキーマの履歴を管理する

MigrationはEntityFramework4.3で採用された機能になります。前回の記事では、起動時のInitializerにDropCreateDatabaseIfModelChangesを指定することでモデルクラスで変更したコードに対してスキーマの同期をとるようにしていましたが、最新の状態のみ管理することになります。これに対してMigrationを使用するとスキーマーの状態の履歴をトラッキングすることができ、さらにMigrationのタイミングでのデータ投入、Index作成、Default値設定などを行うことが可能になります。

インストール

パッケージマネージャコンソールでEnable-Migrationsを実行します。

PM> Enable-Migrations -ContextTypeName [対象のDbContextクラス名]
コンテキストが既存のデータベースを対象にしているかをチェックしています...
データベース初期化子で作成されたデータベースが検出されました。既存のデータベースに対応する移行 '201308011029266_InitialCreate' がスキャフォールディングされました。代わりに自動移行を使用するには、Migrations フォルダーを削除し、-EnableAutomaticMigrations パラメーターを指定して Enable-Migrations を再実行します。
Code First Migrations がプロジェクト MiniBlogSample で有効になりました。

既にモデルがある場合は、実行後にテーブルの初期生成のマイグレーションクラスが Migrationsフォルダの下に作成されます。

namespace MiniBlogSample.Migrations
{
    using System;
    using System.Data.Entity.Migrations;
    
    public partial class InitialCreate : DbMigration
    {
        public override void Up()
        {
            CreateTable(
                "dbo.Messages",
                c => new
                    {
                        MessageID = c.Int(nullable: false, identity: true),
                        Text = c.String(),
                        User = c.String(),
                        CreatedAt = c.DateTime(nullable: false),
                        UpdatedAt = c.DateTime(nullable: false),
                    })
                .PrimaryKey(t => t.MessageID);
            
        }
        
        public override void Down()
        {
            DropTable("dbo.Messages");
        }
    }
}

Upメソッドは、変更をする際に必要なメソッドを記述して、Downメソッドにはその変更を元に戻す際に必要なメソッドを記述します。

また同じMigrationsフォルダにConfigration.csが作成されます。 前回作成した初期データ投入のためのSeed()の中身をこちらのソースに移動します。

namespace MiniBlogSample.Migrations
{
    using System;
    using System.Data.Entity;
    using System.Data.Entity.Migrations;
    using System.Linq;

    internal sealed class Configuration : DbMigrationsConfiguration<MiniBlogSample.Models.MiniBlogSampleDbContext>
    {
        public Configuration()
        {
            AutomaticMigrationsEnabled = false;
        }

        protected override void Seed(MiniBlogSample.Models.MiniBlogSampleDbContext context)
        {
            context.Messages.AddOrUpdate(
            new MiniBlogSample.Models.Message
            {
                Text = "Dummy_Text",
                CreatedAt = DateTime.Now,
                UpdatedAt = DateTime.Now
            });
        }
    }
}

今回は自動Migrationを行わないので

AutomaticMigrationsEnabled = false;

としておきます。

AutomaticMigrationsEnabled = true;

としておくと、Add-Migrationを実行してMigrationファイルを作成しなくても モデルクラスと現在のスキーマを比較して変更点があれば自動的にマイグレーションしてくれます。

最後にGlobal.asax.csのSetInitializerをMigrationを使用するように変更します。

Database.SetInitializer(new MigrateDatabaseToLatestVersion<MiniBlogSampleDbContext, Configuration>());
Migrationの実行
namespace MiniBlogSample.Models
{
    public class Message
    {
        public int MessageID { get; set; }
        public string Text { get; set; }
        public string User { get; set; }
        public DateTime CreatedAt { get; set; }
        public DateTime UpdatedAt { get; set; }
    }
}

に対して、Userカラムを削除します

namespace MiniBlogSample.Models
{
    public class Message
    {
        public int MessageID { get; set; }
        public string Text { get; set; }
        public DateTime CreatedAt { get; set; }
        public DateTime UpdatedAt { get; set; }
    }
}

修正したモデルのコードを保存した後、パッケージマネージャーコンソールで Add-Migrationを実行します。

PM> Add-Migration RemoveColumnUserFromMessage
移行 'RemoveColumnUserFromMessage' をスキャフォールディングしています。
この移行ファイルのデザイン コードには、現在の Code First モデルのスナップショットが含まれています。このスナップショットは次の移行をスキャフォールディングする際、モデルに対する変更の計算に使用されます。モデルに追加の変更を行い、この移行に含める場合は、'Add-Migration 201308060627006_RemoveColumnUserFromMessage' を再実行して再度スキャフォールディングできます。

実行すると、MigrationsフォルダにMigrationのソースが作成されます。

  public partial class RemoveColumnUserFromMessage : DbMigration
    {
        public override void Up()
        {
            DropColumn("dbo.Messages", "User");
        }
        
        public override void Down()
        {
            AddColumn("dbo.Messages", "User", c => c.String());
        }
    }

Initializerで設定しているためアプリケーション起動してDbContextにアクセスしたときに自動でMigrationが起動されますが、 手動でも実行することができます。その際はパッケージコンソールマネージャからUpdate-Databaseを実行します。 オプション -Verboseを付けると実行するSQL文を表示し確認することができます。

PM> Update-Database -Verbose
Using StartUp project 'MiniBlogSample'.
Using NuGet project 'MiniBlogSample'.
ターゲット データベースに適用されている SQL ステートメントを表示するには、'-Verbose' フラグを指定します。
ターゲット データベースは 'MiniBlogSampleDb' (データソース: (LocalDb)\v11.0、プロバイダー: System.Data.SqlClient、原点: Configuration) です。
コードベースの移行を適用しています: [201308011029266_InitialCreate, 201308060627006_RemoveColumnUserFromMessage]。
コードベースの移行を適用しています: 201308011029266_InitialCreate。
CREATE TABLE [dbo].[Messages] (
    [MessageID] [int] NOT NULL IDENTITY,
    [Text] [nvarchar](max),
    [User] [nvarchar](max),
    [CreatedAt] [datetime] NOT NULL,
    [UpdatedAt] [datetime] NOT NULL,
    CONSTRAINT [PK_dbo.Messages] PRIMARY KEY ([MessageID])
)
CREATE TABLE [dbo].[__MigrationHistory] (
    [MigrationId] [nvarchar](255) NOT NULL,
    [Model] [varbinary](max) NOT NULL,
    [ProductVersion] [nvarchar](32) NOT NULL,
    CONSTRAINT [PK_dbo.__MigrationHistory] PRIMARY KEY ([MigrationId])
)
BEGIN TRY
    EXEC sp_MS_marksystemobject 'dbo.__MigrationHistory'
END TRY
BEGIN CATCH
END CATCH
[移行履歴レコードの挿入]
コードベースの移行を適用しています: 201308060627006_RemoveColumnUserFromMessage。
DECLARE @var0 nvarchar(128)
SELECT @var0 = name
FROM sys.default_constraints
WHERE parent_object_id = object_id(N'dbo.Messages')
AND col_name(parent_object_id, parent_column_id) = 'User';
IF @var0 IS NOT NULL
    EXECUTE('ALTER TABLE [dbo].[Messages] DROP CONSTRAINT ' + @var0)
ALTER TABLE [dbo].[Messages] DROP COLUMN [User]
[移行履歴レコードの挿入]
Seed メソッドを実行しています。
PM> 

マイグレーションを最初からやり直したい場合は

PM> Update-Database -Force -TargetMigration:"0"

とやってから、

PM> Update-Database -Force

とします。

チーム開発のための .NET 開発環境の整備(TDDの準備2)

.NETでのチーム開発のための環境整備を社内で作成しているところですが、備忘もかねて作業記録や気が付いた点など書いていきます。


今回はTDD開発進めるにあたり準備することを記載します。

今回の概要

  1. 単体テストフレームワーク(NSpec)
  2. Jenkinsの設定

今回の環境

  • VisualStudio 2012
  • Entity Framework 5.0
  • ASP.NET MVC4
  • Jenkins

1. 単体テストフレームワーク(NSpec)

NSpecRspecのような記述ができるようNUnitを拡張したライブラリです。*1

RSpecはこのような記述でテストコードが記述できるテスティングフレームワークです。

describe Array, "が空の場合:" do
  before do
    @empty_array = []
  end

  it "#empty? は true であること" do
    @empty_array.should be_empty
  end

  it "#size は 0 であること" do
    @empty_array.size.should == 0
  end

  after do
    @empty_array = nil
  end
end

このように記述に振舞いを示す語彙を使用できることで、テストコード自体の可読性を高めようとするものになります。 BDDの準備1でも同様の目的でSpecFlowというテスティングフレームワークを紹介しましたが SpecFlow(Cucumber)は受け入れテストに用い、NSpec(Rspec)はNUnitなどの代わりに単体テストに用いるのが一般的のようです。

インストール

テスト用のプロジェクトを「クラスライブラリ」で作成します。 パッケージマネージャーコンソールを開いて既定のプロジェクトを今作成したテスト用プロジェクトにしてコンソール画面で「Install-Package nspec」と入力してインストールをします。

テストの記述については、Nspecの公式ページにサンプルがありますのでそちらをご覧ください。 また、Nspecの基となったRspecについて以下の記事で理解を深めるとやりやすいと思います。

NspecはNUnitがもとにはなっていますが、テストアダプターが今のところないためにテストエクスプローラから実行させることはできませんので テストを実行するときにはコンソール画面からNSpecRunner.exeを起動してテストを行う必要があります。

NSpecRunnerは、本家サイトからダウンロードできるのですが、バージョン0.9.64.0までしか用意されておらず*2、 先ほどInstall-Packageでいれたバージョン0.9.67.0よりも古いものとなっております。

0.9.64.0でもテスト自体は動かすことができますが、テストのレポートとして用意されているフォーマッターがConsole,HTML,XML,Tidywikiしか用意しておりません ので最新版のソースをGitHubよりダウンロードしてビルドを行ったものを使用してください。

ダウンロードしたフォルダにはVS2010用のソリューションとVS2012用のソリューションが含まれています。 プロジェクト NSpecRunnerをReleaseビルド後 NSpecRunner\bin\Releaseのフォルダから以下のファイルを任意のフォルダにコピーして、PATHを通しておきます。 f:id:kuroyanagi_h:20130802154330p:plain

テストの実行

簡単に以下のようなテストメソッドを書いてみました。(2つ目のテストは誤り) テスト対象のクラス、メソッドには少なくとも1つの_(アンダースコア)が必要です。

using System;
using NSpec;

namespace MiniblogSample.NSpecTests
{
    public class 数値ライブラリ_について : nspec
    {
        void 累乗_を計算したとき()
        {
            it["5の2乗は25であること"] = () => Math.Pow(5,2).should_be(25);
            it["5の3乗は75であること"] = () => Math.Pow(5, 3).should_be(75);
        }
    }
}

コンソール画面から

nspecrunner MiniBlogSample.NSpecTests\bin\Debug\MiniblogSample.NSpecTests.dll (テストメソッドのあるdll)

と入力して実行すると f:id:kuroyanagi_h:20130802161214p:plain 少し見にくいですが、成功メソッドはグリーン、失敗メソッドおよびエラーメッセージはレッド で表示され、最後にテスト総数、失敗したテスト数が表示されます。

開発時はコンソール画面で結果確認し、問題のソースを修正を繰り返す流れになります。

またテストの結果はこのようにコンソール画面で色付けして表示されるほか、--formatter=[フォーマッタクラス名]というオプションにより出力形式を変更できます。

--formatterに指定するクラス名ですが バージョン0.9.67.0では以下の文字列を指定することができます。

  • ConsoleFormatter コンソール画面への出力形式(Default)
  • HtmlFormatter HTML形式 f:id:kuroyanagi_h:20130802163231p:plain
  • TiddlyWikiFormatter TiddyWiki形式(エラーになってしまう??)
  • XmlFormatter XML形式 f:id:kuroyanagi_h:20130802163455p:plain
  • XUnitFormatter XUnit形式(後述のJenkinsではこの形式を用います) f:id:kuroyanagi_h:20130802164234p:plain

すべてにおいて出力は標準出力に出されますので、Windowsのコンソール画面ではすべて文字コードがShiftJISになることに注意してください。

2. Jenkinsの設定
  • プロジェクトの設定 プロジェクトの設定でWindowsバッチコマンドの起動を追加します。 f:id:kuroyanagi_h:20130802164652p:plain
REM NSpec Consoleの実行
rmdir /s /q NSpec.TestResults
mkdir NSpec.TestResults
REM コンソール出力がShiftJISになっているので文字コードをutf-8に変換して書き込む
"NSpecRunner.exe" MiniBlogSample.NSpecTests\bin\Debug\MiniBlogSample.NSpecTests.dll --formatter=XUnitFormatter  | nkf32 -W8  > NSpec.TestResults/NSpec-result.xml

NSpecRunner のオプションで --formatterにXunitFormatterを指定してJenkinsが読める形式でファイルを作成します。 先ほど説明したとおり、出力の文字コードがShiftJISになってしまうためJenkinsで日本語を読むためにはUTF-8に変換する必要があります。 そこで、nkfを使って文字コードを変換したのちファイルに出力させています。(ここでしばらく悩んでいました)

nkf32はVectorなどからダウンロードして利用してください。nkf以外でもUTF-8に変換できればどんなツールでも よいと思います。

NSpecの実行結果をレポートする時に使用するプラグインですが、Jenkinsインストール時にすでに用意されているJUnitテスト結果の集計プラグインが利用できます。 「ビルド後の処理の追加」で「JUnitテスト結果の集計」を選択し上記のNspec実行時に出力したXMLファイルを指定します。

f:id:kuroyanagi_h:20130802165827p:plain

*1:但しNUnitのTestRunnerでは動かないので、あとで苦労した

*2:2013/8/1現在

チーム開発のための .NET 開発環境の整備(DBの準備)

.NETでのチーム開発のための環境整備を社内で作成しているところですが、備忘もかねて作業記録や気が付いた点など書いていきます。


今回は本番とテストでのDB切り替えやスキーマの同期について書きます。

今回の概要

  1. CodeFirstでテーブル作成
  2. テスト・本番用のDB切り替え
  3. Seedで初期データの投入

3のSeedで初期データの挿入までは連載:Entity Framework 4.1入門 by @IT に詳細な説明があります。

今回の環境


1. CodeFirstでテーブル作成

従来はDBスキーマを先に作成し、それに合うようにエンティティクラスを作成するのが普通でしたが、 エンティティクラスのコードを先に記述して、それを元にテーブルが自動生成されるという仕組みが コードファーストです。 もちろん先にDB設計ができている場合はあえてコードファーストを採用する必要はありません。 またコード・ファースト開発においてはRailsのようにCoC(convention over configuration)なのでテーブル名やプロパティ名などいくつかの規約があります。 上記で紹介の記事に詳細が記載されてますので詳しくはそちらを参照ください

モデルの作成
Models/Message.cs
using System;

namespace MiniBlogSample.Models
{
    public class Message
    {
        public int MessageID { get; set; }
        public string Text { get; set; }
        public DateTime CreatedAt { get; set; }
        public DateTime UpdatedAt { get; set; }
    }
}
DbContextの作成
Models/MiniBlogSampleDbContext .cs
using System;
using System.Data.Entity;

namespace MiniBlogSample.Models
{
    public class MiniBlogSampleDbContext : DbContext
    {
        public DbSet<Message> Messages { get; set; }
    }
}
モデル変更時のデータベースとの同期

開発中、エンティティモデルが変更になった際に実際のデータベースを自動的に作成しなおすという機能があります。 これを有効にするためにはApprication_Start()などの中でDropCreateDatabaseIfModelChangesを呼び出します。 開発中のみで行うようReleaseでは無効にしたほうがよいかと思います。

Global.asax.cs
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
            AuthConfig.RegisterAuth();
#if DEBUG
            Database.SetInitializer(new DropCreateDatabaseIfModelChanges<MiniBlogSampleDbContext>());
#endif
        }

この機能はMiniBlogSampleDbContextが初期化されるときに機能します。 したがって通常はDbContextを使用するコントローラにアクセスされたときになります。

2. テスト・本番用のDB切り替え

上記のサイトの説明にあるようにアプリケーション構成ファイル(App.config/Web.config)で接続文字列を設定します。 したがって本番用、テスト用のデータベース接続の切り替えにもアプリケーション構成ファイルを用います。

connectionStringsに下記のように接続文字列を設定します。この時nameは上で作成したDbContextクラスと同じ名前にする必要があります。

Web.config
<?xml version="1.0" encoding="utf-8"?>
<!--
  ASP.NET アプリケーションを構成する方法の詳細については、
  http://go.microsoft.com/fwlink/?LinkId=169433 を参照してください
  -->
<configuration>

  以下省略.....

    <add name="MiniBlogSampleDbContext" connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=MiniBlogSampleDb;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\MiniBlogSampleDbContext_test.mdf" providerName="System.Data.SqlClient" />
  </connectionStrings>
 
  以下省略.....

アプリケーション構成ファイルの切り替えは、ビルド時に行われるのではなくDeploy時に行われるので、Web.configに指定するDBはテスト側にしておいて Web.Release.configに本番側のDBの設定をします。

Web.Release.config
<?xml version="1.0" encoding="utf-8"?>
<configuration xmlns:xdt="http://schemas.microsoft.com/XML-Document-Transform">
  <connectionStrings>
    <add name="MiniBlogSampleDbContext" 
      connectionString="Data Source=(LocalDb)\v11.0;Initial Catalog=MiniBlogSampleDb;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\MiniBlogSampleDbContext.mdf" 
      xdt:Transform="SetAttributes" xdt:Locator="Match(name)"/>
  </connectionStrings>
  <system.web>
  </system.web>
</configuration>

この記述によりWeb.configに指定されている接続文字列をReleaseのデプロイ時に置き換えることができます。

3. Seedで初期データの投入

1.のモデル変更時のデータベースとの同期で指定した Database.SetInitializerをカスタマイズすることで初期必須データの投入*1をさせることができます。

Initializerに指定したDropCreateDatabaseIfModelChangesを継承したクラスを作成してSeedメソッドをオーバライドします。 これで、モデルが変更になった際にはテーブルが再作成されて、合わせてSeedの中でセットしたデータが投入されます。*2

Models/MiniBlogSampleDbInitializer.cs
using System;
using System.Data.Entity;

namespace MiniBlogSample.Models
{
    public class MiniBlogSampleDbInitializer : DropCreateDatabaseIfModelChanges<MiniBlogSampleDbContext>
    {
        protected override void Seed(MiniBlogSampleDbContext context)
        {
            base.Seed(context);

            var message = new Message
            {
                Text = "Dummy_Text",
                CreatedAt = DateTime.Now,
                UpdatedAt = DateTime.Now
            };
            context.Messages.Add(message);
        }
    }
}

global.asax.csの中の

 Database.SetInitializer(new DropCreateDatabaseIfModelChanges<MiniBlogSampleDbContext>());

 Database.SetInitializer(new MiniBlogSampleDbInitializer ());

に変更します。

次回はSetInitializerに追加になったMigration機能とテスト時のDB作成に便利なFabricatorについて記事にします。

*1:マスターデータなど

*2:モデルが再作成されないとセットされません

チーム開発のための .NET 開発環境の整備(BDDの準備1)

.NETでのチーム開発のための環境整備を社内で作成しているところですが、備忘もかねて作業記録や気が付いた点など書いていきます。


今回はBDDおよびブラウザテスト進めるにあたり必要なソフトのインストールを行います。

今回の概要

  1. BDDテストフレームワーク(SpecFlow)
  2. ブラウザ自動テスト(Selenium + Coypu)

今回の環境

  • VisualStudio 2012
  • Entity Framework 5.0
  • ASP.NET MVC4
  • InternetExplorer10
  • Jenkins

NUnitのような単体テストで詳細のメソッドのテストではなく、機能としての仕様をテストし、受け入れテスト としても非プログラマも読むことができるテスト仕様書としても利用可能なフレームワークとして SpecFlowを導入してみます。またSpecFlowを用いたテストとして ブラウザの自動テストを行うためにCoypuを導入したテストを行います。

SpecFlowはRuby界でいうCucumberに影響を大きく受けているフレームワークで Cucumber同様Gherkin書式により仕様を記述することで人にも読むことのできる(日本語でも記述できる) テストの記述が可能です。

CoypuはRuby界でいうCapybaraに相当する、Webブラウザ上の操作を コードで記述できるフレームワークです。これにより「ページを開く」「リンクをクリックする」 「フィールドを埋める」「ラジオボタンを選択する」などのユーザ操作をコードで記述できます。

capybaraとcoypuがどれだけ似ているかは次の画像を見てみてください。

SpecFlowの導入
  1. [ツール]-[拡張機能と更新プログラム]でオンラインからSpecFlowを検索してインストールします。 f:id:kuroyanagi_h:20130731173220p:plain
  2. SpecFlow用のプロジェクトをクラスライブラリで作成します。
  3. パッケージマネージャコンソールを開いて Install-Package SpecFlow と入力します。 f:id:kuroyanagi_h:20130731174923p:plain
coypuの導入
  1. パッケージマネージャコンソールを開いて Install-Package coypu と入力します。 f:id:kuroyanagi_h:20130730135519p:plain coypuと一緒にSelenium.WebDriver,Selenium.Supportがインストールされます。

  2. SeleniumではデフォルトでFirefoxを使用します。InternetExplorerやChromeを使用してテストを行う場合は Seleniumの公式ページから必要なWebDriverをダウンロードします。 IEを使用する場合は「The Internet Explorer Driver Server」をChromeを使用する場合は「chromedriver」 をダウンロードします。

  3. ダウンロードしたWebDriverはテストを行うプロジェクトのbin/debugに入れるか、システムのPATHの通った場所に コピーします。(CIサーバーでもWebDriverが必要になります。binの下はビルド時のクリーンで削除されてしまうので任意のフォルダに入れておきPATHを通しておくとよいでしょう。)

今回はインストール手順までを記載しました。 次回はSpecFlowを用いたテストコードの記載とテストの実行を記載します。