Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Reusing minitest integration tests

I have three pages in Rails that all display the same header, and hence would require the exact same integration tests.

Instead of repeating myself and writing separate tests that look almost exactly the same, what's the best approach here? I've tried putting the shared assertions into a module but haven't been successful getting it to load into each test scenario.

UNDRY:

class IntegrationTest
  describe "page one" do

    before { visit page_one_path }

    it "should have a home page link" do
      page.find_link "Home"
    end
  end

  describe "page two" do

    before { visit page_two_path }

    it "should have a home page link" do
      page.find_link "Home"
    end
  end

  describe "page three" do

    before { visit page_three_path }

    it "should have a home page link" do
      page.find_link "Home"
    end
  end
end

Failed attempt at drying it out...

Module:

/lib/tests/shared_test.rb

module SharedTest

  def test_header
    it "should have a home page link" do
      page.find_link "Home"
    end
  end
end

Test:

class IntegrationTest
  include SharedTest

  describe "page one" do
    before { visit page_one_path }
    test_header
  end

  describe "page two" do
    before { visit page_two_path }
    test_header        
  end

  describe "page three" do
    before { visit page_three_path }
    test_header
  end
end

I haven't quite figured out how to write modules yet so it's no surprise that this doesn't work. Can someone point me in the right direction?

like image 591
Brent Eicher Avatar asked Apr 30 '26 00:04

Brent Eicher


1 Answers

The way to share tests between different describe blocks when using Minitest's spec DSL is to include the module in each describe block you want those tests to run in.

module SharedTest
  def test_header
    assert_link "Home"
  end
end

class IntegrationTest < ActiveDispatch::IntegrationTest
  describe "page one" do
    include SharedTest
    before { visit page_one_path }
  end

  describe "page two" do
    include SharedTest
    before { visit page_two_path }
  end

  describe "page three" do
    include SharedTest
    before { visit page_three_path }
  end
end

One of the ways the Minitest's Test API is different than Minitest Spec DSL is in how they behave when being inherited. Consider the following:

class PageOneTest < ActiveDispatch::IntegrationTest
  def setup
    visit page_one_path
  end

  def test_header
    assert_link "Home"
  end
end

class PageTwoTest < PageOneTest
  def setup
    visit page_two_path
  end
end

class PageThreeTest < PageOneTest
  def setup
    visit page_three_path
  end
end

The PageTwoTest and PageThreeTest test classes inherit from PageOneTest, and because of that they all have the test_header method. Minitest will run all three tests. But, when implemented with the spec DSL the test_header method is not inherited.

class PageOneTest < ActiveDispatch::IntegrationTest
  def setup
    visit page_one_path
  end

  def test_header
    assert_link "Home"
  end

  describe "page two" do
    before { visit page_two_path }
  end

  describe "page three" do
    before { visit page_three_path }
  end
end

In this case, only one test is run. The test class created by describe "page two" will inherit from PageOneTest, but will have all of the test methods removed. Why? Because Minitest's spec DSL is based on RSpec, and this is the way that RSpec works. Minitest goes out of its way to nuke the test methods that are inherited when using the spec DSL. So the only way to share tests while using the spec DSL is to include the module in each describe block you want them to be in. All other non-test methods, including the before and after hooks, and the let accessors, will be inherited

like image 79
blowmage Avatar answered May 01 '26 15:05

blowmage