rails architecture engines rspec rmm

In part one, we created a rails 6 user authentication engine. Part two will focus on testing. The source code is on github.

Testing Our Engine

Source Code

One of the benefits of a modular monolith is the ease of testing. However, each engine must be configured to test in isolation. It would be ideal to extend common test configuration to reduce setup time and keep things consistent across the application. We extracted our config into a gem, common_testing.

Since common_testing is opinionated and can vary across products we use it as a local gem. The gem lives in our host app’s/gems folder. Alternatively, you can read Adding rspec to a rails engine.

Let’s clone common_testing into our gems folder.

./host_app $ mkdir -p ./gems
./host_app $ cd ./gems
./host_app/gems $ git clone https://github.com/amrani/common_testing.git

Bundle and remove git.

./host_app/gems $ cd ./common_testing
./host_app/gems/common_testing $ rm -rf .git
./host_app/gems/common_testing $ bundle install

You will find our shared rails and spec helpers in the lib folder.

Let’s add this gem to our ConnectBy engine.

# engines/connect_by/Gemfile

group :development, :test do
  gem "common_testing", path: "../../gems/common_testing"
end
# engines/connect_by/connect_by.gemspec
spec.add_development_dependency "common_testing"
./host_app/engines/connect_by $ bundle install

Create the engine specific rails and spec helper. Then we can load the shared helper’s from the common_testing gem.

# engines/connect_by/spec/rails_helper.rb

ENGINE_ROOT = Pathname.new(File.expand_path("..", __dir__))
ENV["RAILS_ENV"] = "test"
require "common_testing/shared_rails_helper"
# engines/connect_by/spec/spec_helper.rb

require "bundler/setup"
require "common_testing/shared_spec_helper"

Add a .rspec config file and require our local spec-helper.

./host_app/engines/connect_by $ echo "--require spec_helper" > .rspec

Check if everything is working by running rspec spec in your engines root

./host_app/engines/connect_by $ rspec spec
No examples found.

Finished in 0.00026 seconds (files took 0.08725 seconds to load)
0 examples, 0 failures

Now we should add a test.

# engines/connect_by/spec/models/connect_by/user_spec.rb

require "rails_helper"
RSpec.describe ConnectBy::User, type: :model do
  it { expect(true).to be_truthy }
end

APP_RAKEFILE is configured by ./engines/connect_by/Rakefile to use dummy app’s. That way we can run our migrations in the engine’s root.

When we generated connect_by, we used the option --dummy_path=spec/dummy. Your dummy app should be in ./engines/connect_by/spec/dummy.

NOTE: If you didn’t, you will need to setup a dummy app and update your engine’s Rakefile.

# engines/connect_by/Rakefile
APP_RAKEFILE = File.expand_path("spec/dummy/Rakefile", __dir__)
load "rails/tasks/engine.rake"

Setup the database

The engine’s dummy app, by default, prepends each database with dummy_app. To avoid name collisions with another engine dummy app, let’s alter the database.yml. I’ll use a format with app_name, engine_name, "dummy_app", and env,

# ./engines/connect_by/spec/dummy/config/database.yml
test:
  <<: *default
  database: host_app_connect_by_dummy_test

Now setup our test db and run migrations.

./host_app/engines/connect_by $ RAILS_ENV=test rails db:setup
./host_app/engines/connect_by $ rspec spec
.

Finished in 0.02621 seconds (files took 1.07 seconds to load)
1 example, 0 failures

Factory Bot

I’ll add to my engine’s generators to use factory-bot.

module ConnectBy
  class Engine < ::Rails::Engine
    ...

    config.generators do |g|
      g.test_framework :rspec
      g.fixture_replacement :factory_bot
      g.factory_bot dir: "spec/factories"
    end

Takeway

We added rspec and factory-bot to a rails 6 engine. Our shared configuration and dependencies were added to a local gem and referenced by our engine.

The source code for this part is on github.

Next Steps

In Part 3, we will cover how we pass host app configuration options to our engine.

Useful Resources

I have compiled a list of useful resources for rails engines and the modular monolith architecture.

Scale With Rails Engines

Need help scaling your rails application with a modular monolith? Talk to us


 

Found this useful? Know how it can be improved? Get in touch and share your thoughts at blog@hocnest.com