Testing Thor Ruby Required Options

Testing Thor Ruby Required Options

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 👋