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 👋