Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

unit testing a ruby command line application's code - how to simulate/pass ARGV's

I have a command-line application which uses thor to handle the parsing of options. I want to unit test the command-line functionality against the code with test-unit and/or minitest.

I can't seem to figure out how to make sure the ARGV array (which normally would hold the options from the command line) holds my test options so they can be tested against the code.

The specific application code:

# myapp/commands/build.rb
require 'thor'

module Myapp
  module Commands

    # Define build commands for MyApp command line
    class Build < Thor::Group
      include Thor::Actions

      build = ARGV.shift
      build = aliases[build] || build

      # Define arguments and options
      argument :type
      class_option :test_framework, :default => :test_unit

      # Define source root of application
      def self.source_root
        File.dirname(__FILE__)
      end

      case build

      # 'build html' generates a html
      when 'html'

        # The resulting html
        puts "<p>HTML</p>"
      end
    end
  end
end

The executable

# bin/myapp

The Test File

# tests/test_build_html.rb

require 'test/unit'
require 'myapp/commands/build'


class TestBuildHtml < Test::Unit::TestCase
  include Myapp::Commands

  # HERE'S WHAT I'D LIKE TO DO
  def test_html_is_built

    # THIS SHOULD SIMULATE 'myapp build html' FROM THE COMMAND-LINE
    result = MyApp::Commands::Build.run(ARGV << 'html')
    assert_equal result, "<p>HTML</p>"
  end

end

I have been able to pass an array into ARGV in the test class, but once I call Myapp/Commands/Build the ARGV appears to be empty. I need to make sure the ARGV array is holding 'build' and 'html' in order for the Build command to work and this to pass.

like image 275
Dave Thompson Avatar asked Dec 24 '11 00:12

Dave Thompson


People also ask

How do I run a test case in Ruby?

We can run all of our tests at once by using the bin/rails test command. Or we can run a single test file by passing the bin/rails test command the filename containing the test cases.

What is the testing framework for Ruby?

test-unit (Test::Unit) is unit testing framework for Ruby, based on xUnit principles. These were originally designed by Kent Beck, creator of extreme programming software development methodology, for Smalltalk's SUnit. It allows writing tests, checking results and automated testing in Ruby.


2 Answers

The easiest way to set ARGV and avoid warning is to do:

ARGV.replace your_argv

Found in http://apidock.com/ruby/Test/Unit/setup_argv/class

like image 147
leemour Avatar answered Oct 07 '22 01:10

leemour


A better pattern would be to abstract out the direct usage of ARGV for testing. Given your current design, you could make a module called something like CommandLineArguments and provide access that way:

module CommandLineArguments
  def argv; ARGV; end
end

In your main code:

class Build < Thor::Group
  include CommandLineArguments
  include Thor::Actions

  args = argv
  build = args.shift

Finally, in your test, you can modify the module or your test class:

def setup
  @myargs = nil
end

class MyApp::Commands::Build
  def argv; @myargs || ARGV; end
end

def test_html_is_built
  @myargs = %w(html)
  result = MyApp::Commands::Build.run
end

If this seems rather complex, it is. You might be better served by extracting the majority of your code into actual classes and then use them in your Thor-powered executable (rather than having all that code in the executable).

like image 26
davetron5000 Avatar answered Oct 07 '22 00:10

davetron5000