I built a Thor script that connects to an HTTP API to perform some very simple actions. I've coded tests for the backend but the Thor script is basically untested, which is quite suboptimal.
My first approach was to capture the output of the commands itself and write test against such output, the resulting tests are unsurprisingly slow.
expect(`bin/script foo`).to eq('bar')
I then tried to use both webmock
and vcr
but using this approach none of these frameworks are invoked, even if I mock the exact request the mock is unused, most probably because both webmock
and vcr
are unable to hook into the thor script.
Has anybody found a nice solution for this? Invoking the Thor script directly (Thorclass.action('bar')
) would be enough for my taste, but I haven't found a way to do it.
Any suggestion? Thanks in advance.
bin/seed
#!/usr/bin/env ruby
require "thor"
class Seed < Thor
desc "budgets", "Seeds budgets"
def budgets
puts 'Seeding currencies...'
SeedBudgets.new.call
puts 'Done.'
end
end
Seed.start
For more details on command line Thor see this excellent walkthrough
lib/services/seed_budgets.rb
class SeedBudgets
def initialize
# I find an initialize helpful for injecting dependencies
end
def call
# Code goes here
end
end
test/services/seed_budgets_test.rb
require 'minitest/autorun'
require 'vcr'
VCR.configure do |config|
config.cassette_library_dir = 'fixtures/vcr_cassettes'
config.hook_into :webmock
end
class SeedBudgetsTest < Minitest::Test
def test_seeds_one_budget
VCR.use_cassette('one_budget_from_api') do
SeedBudgets.new.call
assert_equal 1, Budget.count
end
end
end
That will allow you to decouple the command line interface from the actual code.
Then Thor becomes a very thin wrapper around your actual code.
Feel free to post more detailed code and I can help more. :)