こんにちは。エンジニアのTsujimotoです。弊社では、広告クリエイティブのクラウド収集サービス「アドクロール」をRuby on Railsで開発しています。 前回、Bitbucket上で利用できるCI/CDツール「Bitbucket Pipelines」を用いて、RailsアプリのRSpecを自動実行する方法をご紹介しました。今回は、非Railsのバッチ処理(Ruby + ActiveRecord)のRSpecをBitibucket Pipelinesで実行する方法をご紹介します。Bitbucket Pipelinesの概要や基本的な使い方は前回の記事をご覧ください。

Railsのプロジェクトでは、テーブル定義をマイグレーションで管理していれば簡単にテスト用テーブルを作れますが、今回はそうはいきません。db:migrateなどのRakeタスクが使えないためです。今回は、テーブル定義をMySQLのダンプファイルで管理して、テスト用Docker環境にMySQLクライアントをインストールした状態で、ダンプをインポートする という風にセットアップします。

サンプルファイル

次のようにテーブル定義・バッチファイル・テストファイル・DB接続定義ファイルを用意し、ユーザごとのポスト数を更新するバッチをテストしてみます。

  
# テーブル定義:schema.sql
-- Create syntax for TABLE 'users'
CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `age` int(11) DEFAULT NULL,
  `post_count` int(11) DEFAULT '0',
  `created_at` datetime(6) NOT NULL,
  `updated_at` datetime(6) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

-- Create syntax for TABLE 'posts'
CREATE TABLE `posts` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) NOT NULL,
  `content` varchar(127) DEFAULT NULL,
  `created_at` datetime(6) NOT NULL,
  `updated_at` datetime(6) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `user_id` (`user_id`),
  CONSTRAINT `posts_ibfk_1` FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
  
  
# バッチファイル:update_posts_count.rb
require './database'

User.joins(:posts).find_each do |user|
  user.update(post_count: user.posts.count)
end
  
  
# テストファイル:spec/batch_spec.rb
require_relative '../database'
require 'spec_helper'

RSpec.describe "バッチテスト サンプル" do
  it 'ユーザのポスト数を更新する' do
    user = User.create(name: 'ユーザ01', age: 30, post_count: 0)
    Post.create(user: user, content: 'ポスト01')
    Post.create(user: user, content: 'ポスト02')

    # バッチ実行
    `bundle exec ruby update_posts_count.rb`

    expect(User.find(user.id).post_count).to eq 2
  end
end
  
  
# DB接続定義:database.rb
require 'active_record'

ActiveRecord::Base.establish_connection(
  adapter: 'mysql2',
  database: 'sample_app_test',
  host: '127.0.0.1',
  username: 'sample_app_test',
  password: 'password'
)

class User < ActiveRecord::Base
  has_many :posts
end

class Post < ActiveRecord::Base
  belongs_to :user
end
  

bitbucket-pipelines.yml を設定

下記の通りにbitbucket-pipelines.ymlを設定します。apt-getでmysqlクライアントをインストールし、mysqlコマンドでインポートしてRSpecを実行しています。

  
pipelines:
  default:
    - step:
        image: ruby:2.6.6
        script:
          - apt-get update && apt-get install -y default-mysql-client
          - gem install bundler
          - bundle install
          - mysql -u sample_app_test -ppassword -h 127.0.0.1 sample_app_test < schema.sql
          - bundle exec rspec spec/batch_spec.rb
        services:
          - db
definitions:
  services:
    db:
      image: mysql:5.7
      environment:
        MYSQL_DATABASE: sample_app_test
        MYSQL_RANDOM_ROOT_PASSWORD: 'yes'
        MYSQL_USER: sample_app_test
        MYSQL_PASSWORD: password
    

パイプラインの実行

bitbucket-pipelines.yml をコミットした状態でプッシュすると自動的にパイプラインが実行されます。下記の通り、テストが実行され成功しています。

終わりに

今回は、Bitbucket Pipelinesを用いて、非RailsプロジェクトのRSpecを自動実行する方法をご紹介しました。ちなみに、今回はymlファイルにmysqlクライアントの設定を書いているので、毎回インストールするところからはじまりますが、下記のようなイメージを作ってホスティングすればクライアントのインストールを省略してテストを高速化できます。

  
FROM ruby:2.6.6

RUN apt-get update && apt-get install -y default-mysql-client
  
Pocket