他人のブログを読んだり、勉強会等のLTを聴いて感じること

こんにちは。

他人のブログを読んでいたり、勉強会や某ABCに参加してLTとか聴いていて感じたことを書きます。

1. お前のブログはオリジナリティがあるのか?
既知の内容なのに、そういった内容をブログに書いている人をよく見かけます。参考サイトのリンクを張っていればまだ許せますが、そういったものがないブログもあります。また、本に載っていることを書いているブログも見かけます。例えば、最近見かけたのでは、iOSでのUITableViewの使い方とか。これはひどいと思いました。お前が考案したAPIなのか?w

2. お前のブログは、どこかのサイトのページの翻訳ではないか?
Androidに関して、キーワードで日本語サイトをググると、Googleのドキュメントリファレンスのページをほぼ翻訳したページを見かけることがあります。ブログを書いている本人は、日本人のために翻訳してあげているんだとか言いそうですが、ブログ中に出てくるサンプルコードも、元のドキュメントリファレンスのページと同じことが多々あります。真っ先に日本語に訳して、日本で最先端を行っているとでも思っているのでしょうか。技術的にとんがりたいなら、自分で作ったサンプルアプリのコードでも載せて欲しいですね。また、最近見かけたブログでは、英語圏のブログのほぼ翻訳で、コード断片もコピペで、元のコードの、作者独自定義の定数を、定義もせずに(定義を引用もせずに)使用している例がありました。元の英語圏のブログでは、githubにサンプルコードがあったので、定数の定義を見ることができましたが、翻訳サイトでは、githubへのリンクは張られていませんでした。

3. 勉強会や某ABCのLTで笑いを取ることしかしない
勉強会や某ABCに参加してLTを聞いていると、次のようなことがあります。

a. アニメの画像をスライドに入れる。
面白くないですし、あなたは、そのアニメの作者に、画像の使用許諾を取ったのですか?

b. 奇声を上げて笑いをとろうとする
勉強会では見かけないですが、某ABCのLTではよく見かけます。ちっとも面白くないです。ビジネス、技術アピールで注目を浴びるようにして下さい。

c. その他
某ABCのLTで、当時流行っていた某ゲームアプリを、某テストツールで動かすことをやったLTがありました。はっきり言って、技術的に面白くないです。自分のプロダクトをテストツールで動かすのならいいですが、そうでないなら、単に笑いを取るだけの内容ですね。

RailsのオリジナルRakeタスクのテスト rspec 3.0.x編

モリジュン(@zyunnosuke)氏が、RailsでオリジナルRakeタスク作成からRSpecテストまでの記事において、Rakeタスクの作り方、RSpecによるテストの仕方を解説してます。その記事では、RSpecは2.x系で、テストコードで、shouldを使っています。今回、RSpec 3.0.xで、expectを使いたいので、挑戦してみました。

1. プロジェクトの作成

$ rails new rake-test-sample
$ cd rake-test-sample
$ bundle update
$ bundle install

2. モデルの作成

rakeのタスクの内容をクラスに抽出したものとして、モデル ReportGeneratorを作成する。

$ rails generate model report_generator
$ bundle exec db:migrate

モデルクラス ReportGeneratorには、次の内容を記述。

class ReportGenerator < ActiveRecord::Base
  def self.generate
    puts "ReportGenerator.generate called."
  end
end
&#91;/ruby&#93;

クラスメソッドで、ダミーな処理を記述している。

3. Rakeタスクファイルの作成

&#91;bash&#93;
$ rails generate task reports
&#91;/bash&#93;

生成されたlib/tasks/repots.rakeに次の内容を記述。元記事のまんまです。

&#91;ruby&#93;
namespace :reports do
  # descの記述は必須
  desc "Generate report"

  # :environmentはモデルにアクセスするのに必須
  task :generate => :environment do
    # 処理を記述
    ReportGenerator.generate
  end
end

タスクの確認は

$ rake -vT |grep reports
rake reports:generate                   # Generate report

タスクの実行は

$ rake reports:generate

4. Gemfileにrspecとrspec-its の追加

元記事では、specファイルで、itsを使っていますが、itsはrspec 3.0.xではサポートされなくなりました。RSpec の入門とその一歩先へ、第3イテレーション ~RSpec 3バージョン~によると、gem rspec-itsを導入すると、itsが使えるとのことです。そこで、元記事に書かれていたrake_shared_context のgemと共に、Gemfileに以下を追加。

group :development, :test do
  gem 'rake_shared_context'
  gem 'rspec-rails', '3.0.0'
  gem 'rspec-its', '1.0.1'
end
$ bundle update
$ bundle install

を実行。

5. RakeタスクのRSpecの作成

rspecによるテストが出来るように次のコマンドを実行します。

$ bundle exec rails generate rspec:install

元記事では、spec/lib/tasks/reports_rake_spec.rbファイルは、次の内容でした。

require 'spec_helper'

describe 'reports:generate' do
  include_context 'rake'

  its(:prerequisites) { should include('environment') }

  it 'generates the report' do
    ReportGenerator.should_receive(:generate)
    subject.invoke
  end
end

これは、rspec 2.x向けの記述なので、次のように書き換えます。

require 'spec_helper'

describe 'reports:generate' do
  include_context 'rake'

  its(:prerequisites) { is_expected.to include('environment') }

  it 'generate the report' do
    expect(ReportGenerator).to receive(:generate)
    subject.invoke
  end
end

記述の仕方は、RSpec の入門とその一歩先へ、第3イテレーション ~RSpec 3バージョン~ や、RSpec 3の重要な変更を参考にしました。

6. Rakeテストの実行

$ bundle exec rspec spec/lib/tasks/reports_rake_spec.rb

warningが多いので、プロジェクトディレクトリの .rspecファイルで、–warningsの行を削除しておきます。

`find_and_eval_shared’: Could not find shared context “rake” (ArgumentError)

というエラーが出ますが、spec/spec_helper.rbの冒頭に次の記述をします。

# This file is copied to spec/ when you run 'rails generate rspec:install'
ENV["RAILS_ENV"] ||= 'test'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'rspec/autorun'

この記述は、パーフェクトRuby on Railsを参考にしました。

再度、テストを実行。

$ bundle exec rspec spec/lib/tasks/reports_rake_spec.rb
...
Finished in 0.01324 seconds (files took 1.22 seconds to load)
2 examples, 0 failures

テストが通りました。

7. ソースの公開場所

andropenguin/rake-test-sample

8. Special Thanks

Rails3レシピブック”モックやスタブを使う”のコードを書き換えてみた

Rails3レシピブックの”モックやスタブを使う”のテストコードは、rspec-mocksのバージョンが古く、バージョン 2.14.6では書き換える必要があります。Rubyにおけるモック、スタブについては自分は初心者なので、試行錯誤して、書き換えてみました。最後のテストの部分は、本によると、失敗するはずなのですが、なぜか通ってしまいます。この点は理解不足なので、保留にします。コードは、GitHubにおいてあります。

https://github.com/andropenguin/samplecode-stub-mock

Rails 4.0.0、RSpec、Capybara使用プロジェクト向けGemfile

Ruby on Rails チュートリアルの、Ruby on Rails 4向けの記事を読んでいます。記事に書いてあるGemfileだと、依存関係がおかしく、buundle installでエラーになります。うまくいくGemfileを示します。

source ‘https://rubygems.org’
ruby ‘2.0.0’

gem ‘rails’, ‘4.0.0’
gem ‘bootstrap-sass’, ‘2.3.2.0’
gem ‘bcrypt-ruby’, ‘3.0.1’
gem ‘faker’, ‘1.1.2’
gem ‘will_paginate’, ‘3.0.4’
gem ‘bootstrap-will_paginate’, ‘0.0.9’

group :development, :test do
gem ‘sqlite3’, ‘1.3.7’
gem ‘rspec-rails’, ‘2.13.1’
# The following optional lines are part of the advanced setup.
# gem ‘guard-rspec’, ‘2.5.0’
# gem ‘spork-rails’, github: ‘sporkrb/spork-rails’
# gem ‘guard-spork’, ‘1.5.0’
# gem ‘childprocess’, ‘0.3.6’
end

group :test do
gem ‘selenium-webdriver’, ‘2.0.0’
gem ‘capybara’, ‘2.1.0’
gem ‘factory_girl_rails’, ‘4.2.0’
gem ‘cucumber-rails’, ‘1.3.0’, :require => false
gem ‘database_cleaner’, github: ‘bmabey/database_cleaner’

# Uncomment this line on OS X.
# gem ‘growl’, ‘1.0.3’

# Uncomment these lines on Linux.
# gem ‘libnotify’, ‘0.8.0’

# Uncomment these lines on Windows.
# gem ‘rb-notifu’, ‘0.0.4’
# gem ‘win32console’, ‘1.3.2’
end

#gem ‘sass-rails’, ‘4.0.2’
gem ‘sass-rails’, ‘4.0.0’
gem ‘railties’, ‘4.0.0’
gem ‘uglifier’, ‘2.1.1’
gem ‘coffee-rails’, ‘4.0.0’
gem ‘jquery-rails’, ‘2.2.1’
gem ‘turbolinks’, ‘1.1.1’
gem ‘jbuilder’, ‘1.0.2’

group :doc do
gem ‘sdoc’, ‘0.3.20’, require: false
end

group :production do
gem ‘pg’, ‘0.15.1’
gem ‘rails_12factor’, ‘0.0.2’
end

gem ‘protected_attributes’

gem ‘execjs’
gem ‘therubyracer’

基礎Ruby on Rails改訂新版のサンプルアプリでFakerを使ってみた

最近、Everyday Rails – RSpecによるRailsテスト入門という電子書籍を読んで、RSpecでテストコードを書くことに取り組んでいます。練習として、基礎Ruby on Rails改訂新板のサンプルアプリにRSpecでテストコードを書きました。Memberクラスは、次のようなバリデーションがあります。

class Member < ActiveRecord::Base
  include EmailAddressChecker

  attr_accessible :number, :name, :full_name, :email, :birthday, :gender, :administrator
  validates :number, presence: true,
            numericality:  { only_integer: true,
            greater_than: 0, less_than: 100, allow_blank: true },
            uniqueness: true
  validates :name, presence: true,
            format: { with: /\A&#91;A-Za-z&#93;\w*\z/, allow_blank: true,
                      message: :invalid_member_name },
            length:  { minimum:  2, maximum:  20, allow_blank: true },
            uniqueness: { case_sensitive: false }
  validates :full_name, length: { maximum:  20 }
  validate :check_email
  validates :gender, inclusion: { in: 0..1 }

  private
    def check_email
      if email.present?
        errors.add(:email, :invalid) unless well_formed_as_email_address(email)
      end
    end

    class << self
      def search(query)
        rel = order("number")
        if query.present?
          rel = rel.where("name LIKE ? OR full_name LIKE ?",
                        "%#{query}%", "%#{query}%")
        end
        rel
      end
    end
end
&#91;/ruby&#93;

FactoryGirl gemとFaker gemを使って、テストデータを生成しました。

&#91;ruby&#93;
require 'faker'

FactoryGirl.define do
  factory :member do
    sequence(:number) { |n| n unless n > 99 }
    name {
      name = Faker::Name.first_name.slice!(0, 19).capitalize
      name if name.length >= 2
    }
    full_name { Faker::Name.name.slice!(0, 19) }
    email {Faker::Internet.email }
    birthday "1981-12-01"
    gender { Faker::Number.number(1).to_i % 2 }
    administrator false

    factory :invalid_member do
      name nil
    end
  end
end

この場合、テストコードを書くと、英語環境ではテストは失敗しません。ところが、i18nで国際化して、日本語環境でテストすると、fakerは国際化に対応しているようで、nameが日本語になったり、emailが不正な表現になって失敗するようになります。バリデーションでは、nameは英字で始まり、英数字からならないとダメだからです。しかし、full_nameについては、日本語のデータが生成されるようにしたいです。fakerのサイトページを見ると、Faker::Config.locale でロケールをスイッチできるようです。そこで、次のファイルを使ってテストデータを生成するようにしました。

require 'faker'

FactoryGirl.define do
  factory :member do
    sequence(:number) { |n| n unless n > 99 }
    name {
      Faker::Config.locale = 'en-us'
      name = Faker::Name.first_name.slice!(0, 19).capitalize
      name if name.length >= 2
    }
    full_name {
      Faker::Config.locale = 'ja'
      Faker::Name.name.slice!(0, 19)
    }
    email {
      Faker::Config.locale = 'en-us'
      Faker::Internet.email
    }
    birthday "1981-12-01"
    gender { Faker::Number.number(1).to_i % 2 }
    administrator false

    factory :invalid_member do
      name nil
    end
  end
end

Faker::Config.locale でロケールをスイッチすると、その後は設定したロケールのままになると期待したのですが、そのようにはならないようで、各フィールドごとにロケールをスイッチしないとダメでした。このテストデータを使用すると、テストが通るようになりました。