Feedback on Hanami Minitest

Hi everyone — I’m pleased to share that our initial Minitest support is now merged into the gem’s main branch.

I’ve implemented the block-based test/setup/teardown API, as you suggested above (with some tweaks to make it fit better with setup and teardown methods in superclasses).

I decided to host the base classes inside the gem. They exist as Hanami::Minitest::{Test,RequestTest,FeatureTest}. I’ve also take the opportunity to use this as a first foray into internalising some of the test setup code (in those same classes) rather than generating everything into the user’s app.

I’d love for you to check it out and please share any other thoughts you might have!

@jaredwhite so far I haven’t implemented first-class support for minitest/spec, simply as a matter of needing to draw the line somewhere and balance my work for Hanami’s upcoming release. I’d definitely love for us to have this in the future. And in the meantime, I think a dedicated minitest/spec user can take matters into their own hands and manually add extend Minitest::Spec::DSL line directly into test/support/minitest.rb, just as you shared.

I’ve added a --test switch to the hanami new command, so users will be able to run hanami new --test=minitest my_cool_app.

See below for an overview of our Minitest support as I have merged it.


Set up everything we need to have Hanami Minitest to work as a full alternative to Hanami RSpec.

Provide three base classes, hosted within the gem:

  • Hanami::Minitest::Test (inherits from Minitest::Test)
  • Hanami::Minitest::RequestTest (includes Rack::Test::Methods and defines the app)
  • Hanami::Minitest::FeatureTest (includes the Capybara DSL/assertions, sets up Capybara, and includes a teardown to reset Capybara’s state)

Enhance Hanami::Minitest::Test with a block-based class-level DSL providing test "my test" do, setup do and teardown do methods.

Provide these CLI command hooks:

  • hanami install, which generates the full setup (this will eventually run as part of hanami new once we provide an option to choose Minitest for testing)
  • generate slice
  • generate action
  • generate part

A full Hanami Minitest setup does the equivalent of everything we do with Hanami RSpec. It creates this structure:

test
├── requests
│   └── root_test.rb
├── support
│   ├── db
│   │   └── cleaning.rb
│   ├── db.rb
│   ├── features.rb
│   ├── minitest.rb
│   ├── operations.rb
│   └── requests.rb
└── test_helper.rb

test_helper.rb is the test setup entry point and should be required from the top of each test file:

require "pathname"
TEST_ROOT = Pathname(__dir__).realpath.freeze

ENV["HANAMI_ENV"] ||= "test"
require "hanami/minitest"
require "hanami/prepare"

require_relative "support/minitest"
TEST_ROOT.glob("support/**/*.rb").each { |f| require f }

support/minitest.rb is for adding any behaviour that should appear in every test:

class Hanami::Minitest::Test
  # Add helper methods to be used by all tests here.
end

support/operations.rb is for making Success and Failure available directly in every test. It serves as an example of how you can use “topic”-specific support files, how not everything needs to be grouped by its top-level test type.

require "dry/monads"

class Hanami::Minitest::Test
  # Provide `Success` and `Failure` for testing operation results.
  include Dry::Monads[:result]
end

support/requests.rb is for customising request tests:

class Hanami::Minitest::RequestTest
  # Add custom request test helpers here.
end

support/features.rb is for customising (Capybara) feature tests:

class Hanami::Minitest::FeatureTest
  # Add custom feature test helpers here.
end

support/db.rb sets up tests that need to use the database. Right now it mostly bring in the TestSupport::DB::Cleaning module, which configures DatabaseCleaner in the same way we do for RSpec:

require_relative "features"
require_relative "db/cleaning"

module TestSupport
  module DB
    def self.included(mod)
      mod.include DB::Cleaning
    end

    # Add helper methods to be used by DB tests here.
  end
end

class FeatureTest
  include TestSupport::DB
end

In terms of the actual test files we generate, here’s an example from running hanami generate action posts.show, test/actions/posts/show_test.rb:

# frozen_string_literal: true

require "test_helper"

class MinitestExample::Actions::Posts::ShowTest < Hanami::Minitest::Test
  test "works" do
    params = {}
    response = MinitestExample::Actions::Posts::Show.new.call(params)
    assert_predicate response, :successful?
  end
end

We create test classes:

  • Whose names match their corresponding class, with Test appended
  • Using the compact class definition format, to keep the file compact and not nested n-levels deep (users will need to fully or selectively disable the Style/ClassAndModuleChildren RuboCop cop in their apps to let these stay)
  • Using the test block-based method
  • With a very simple starter test
1 Like