shou2017.com
JP

Testing Model Validations with Minitest in Rails

Sun Mar 31, 2019
Sat Aug 10, 2024

While RSpec is the mainstream testing framework for Rails, I personally prefer Minitest for its clarity and simplicity.

Here are my notes on testing model validations with Minitest.

Models to Test

We’ll test private brands sold by retail companies like SEIYU or Matsumoto Kiyoshi.

Retailer: SalesCompany model

class SalesCompany < ApplicationRecord
  has_many :product_brands, dependent: :destroy

  # validates
  validates :sales_company_name, presence: true, uniqueness: true
end

Private Brand: ProductBrand model

class ProductBrand < ApplicationRecord
  belongs_to :sales_company

  # validates
  validates :product_brand_name, presence: true, uniqueness: true
end

Writing Test Code

Minitest comes standard with Rails, so there’s no need to install anything extra.

When you create a model, test models and fixtures are automatically created in the test directory.

Here’s what the validation tests for the SalesCompany and ProductBrand models look like:

# test/models/sales_company_test.rb
require 'test_helper'

class SalesCompanyTest < ActiveSupport::TestCase
  setup do
    @sales_company = sales_companies(:seiyu)
  end

  test "SalesCompany is valid" do
    assert @sales_company.valid?
  end

  test "sales_company_name is required" do
    @sales_company.sales_company_name = nil

    assert @sales_company.invalid?
    assert_includes @sales_company.errors[:sales_company_name], "can't be blank"
  end

  test "sales_company_name must be unique" do
    duplicate_sales_company = @sales_company.dup
    duplicate_sales_company.sales_company_name = @sales_company.sales_company_name
    assert_not duplicate_sales_company.valid?
  end
end
# test/models/product_brand_test.rb
require 'test_helper'

class ProductBrandTest < ActiveSupport::TestCase
  setup do
    sales_company = sales_companies(:seiyu)
    @product_brand = product_brands(:minasamano_osumitsuki)
  end


  test "ProductBrand is valid" do
    assert @product_brand.valid?
  end

  test "product_brand_name is required" do
    @product_brand.product_brand_name = nil

    assert @product_brand.invalid?
    assert_includes @product_brand.errors[:product_brand_name], "can't be blank"
  end

  test "product_brand_name must be unique" do
    duplicate_product_brand = @product_brand.dup
    duplicate_product_brand.product_brand_name = @product_brand.product_brand_name
    assert_not duplicate_product_brand.valid?
  end
end

Fixtures

Minitest’s fixtures are intuitive and easy to understand.

You can use them like sales_companies(:seiyu).

# sales_companies.yml
matsumotokiyoshi:
  sales_company_name: matsumotokiyoshi

seiyu:
  sales_company_name: seiyu

seven_eleven:
  sales_company_name: seven-eleven
# product_brands.yml
matsumotokiyoshi:
  sales_company_name: matsumotokiyoshi

seiyu:
  sales_company_name: seiyu

seven_eleven:
  sales_company_name: seven-eleven

プロを目指す人のためのRuby入門[改訂2版] 言語仕様からテスト駆動開発・デバッグ技法まで

See Also