There are lots of tutorials for building a CLI with Thor from scratch, but there aren't a lot of them on how to test it, especially covering scenarios such as required options. This post is about testing Thor Ruby options.
Thor Ruby gem is a great tool to quickly build a CLI (Command-line interface) app.
Although there are lots of tutorials for building a CLI with Thor from scratch, there aren’t a lot of them on how to test it, especially covering scenarios such as required options.
Thor makes it easy to specify options and arguments for Thor commands. However, I didn’t find it easy to test them in the documentation.
If you’ve been searching for tutorials on how to test Thor with required options, this post is for you ⚡
Thor Ruby CLI with options
CatsExample reads cats information from a file, and provides the option to pass a cat id to return information about a specific cat.
Here is an example of the implementation:
module CatsExample
class CLI < Thor
check_unknown_options!
package_name "CatsExample"
def self.exit_on_failure?
true
end
desc "cats", "Displays all cats and their owner's name"
def cats
Cat.new.display_cats_summary
end
desc "cat", "Displays the summary for a given cat"
option :cat_id, type: :string, aliases: "-c", required: true
def cat
cat_id = options[:cat_id] if options
Cat.new.display_cat_summary(cat_id)
end
end
end
This is how the user can interact with our app through the command-line:
# to get a summary of all cats, run:
bundle exec exe/cats_example cats
# to fetch information about a specific cat with a cat_id, run:
bundle exec exe/cats_example cat -cat 100
# or with the `-c` alias:
bundle exec exe/cats_example cat -c 100
How to test Thor required options
To test Thor required options, this is what we have to do:
-
call the method:
:cats -
add an empty string for the arguments:
[] -
add the options inside brackets:
{cat_id: "100"}
Here is the RSpec file:
RSpec.describe CatsExample do
describe "#cat" do
context "when the cat exists" do
it "displays the cat summary" do
expect do
# This is how to test Thor arguments and options <--------
CatsExample::CLI.new.invoke(:cat, [], {cat_id: "100"})
.to output(
a_string_including("Name: Bob Cat")
).to_stdout
end
end
end
context "when the cat does not exist" do
it "displays a message" do
expect do
# This is how to test Thor arguments and options <--------
CatsExample::CLI.new.invoke(:cat, [], {cat_id: "10000"})
.to output(
a_string_including("Cat with cat_id '10000' not found. Try with a different cat_id.")
).to_stdout
end
end
end
end
describe "#cats" do
it "lists the cat and the summary of cats" do
expect do
# This is how to test Thor Ruby invoke call <--------
CatsExample::CLI.new.invoke(:cats).to output(
a_string_including("You have 2 beautiful cats")
).to_stdout
end
end
end
end
Testing more Thor commands
This CLI example didn’t provide extra configurations. Let’s say we had an extra configuration called meow.Here’s how we would test it:
expect do
# This is how to test Thor Ruby invoke call with arguments, options, and extra_configuration <--------
(CatsExample::CLI.new.invoke(:cat, [], {cat_id: "100"}, :extra_configuration => "meow").meow)
.to output(
"meow meow 🐱🚀"
).to_stdout
end
Here is an example from the Thor library.
Now our CLI app handles the scenarios of when a cat can be found, and when it can’t 🐱💻.
I hope this post saves you time and frustration. I couldn’t find examples of how to test required options, so it took me some time to figure it out.
See you in the next post 👋