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

4

7

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.

Inbred answered 24/12, 2011 at 0:6 Comment(0)
H
7

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

Herniorrhaphy answered 14/12, 2013 at 10:9 Comment(0)
D
2

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).

Debug answered 31/12, 2011 at 18:39 Comment(1)
Thanks, Dave! Exactly what I was looking for. In the meantime I ended up reading your book Building Awesome Command-Line Applications in Ruby. ;-) I implemented aruba with cucumber to at least get the acceptance testing going.Inbred
P
1

ARGV.concat %w{build html}, for example?!

Pehlevi answered 18/5, 2015 at 17:51 Comment(0)
G
0

Have you tried ARGV = ['build', 'html']?

You may get a warning but it should give you the desired affect.

According to this you shouldn't even need to use ARGV at all.

Georgena answered 24/12, 2011 at 20:4 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.