-
Notifications
You must be signed in to change notification settings - Fork 552
Integrating with Aruba In Process Runs
r edited this page Jun 16, 2017
·
9 revisions
Aruba is a cucumber library for writing BDD specs for command-line applications. By default it executes the given commands in a separate child process which is both slower, and does not provide the ability to easily stub or mock components. While BDD argues against significant stubbing and mocking, sometimes it is unavoidable if your Thor application depends on external services.
Aruba outlines the process for configuring your CLI app to handle dependency injection allowing same-process test runs however it is not immediately obvious how to integrate this with Thor. The key is to put a wrapper between your binary and your Thor
class like so:
#!/usr/bin/env ruby
require 'mycli/runner'
MyCli::Runner.new(ARGV.dup).execute!
require 'mycli/app'
module MyCli
class Runner
# Allow everything fun to be injected from the outside while defaulting to normal implementations.
def initialize(argv, stdin = STDIN, stdout = STDOUT, stderr = STDERR, kernel = Kernel)
@argv, @stdin, @stdout, @stderr, @kernel = argv, stdin, stdout, stderr, kernel
end
def execute!
exit_code = begin
# Thor accesses these streams directly rather than letting them be injected, so we replace them...
$stderr = @stderr
$stdin = @stdin
$stdout = @stdout
# Run our normal Thor app the way we know and love.
MyCli::App.start(@argv)
# Thor::Base#start does not have a return value, assume success if no exception is raised.
0
rescue StandardError => e
# The ruby interpreter would pipe this to STDERR and exit 1 in the case of an unhandled exception
b = e.backtrace
@stderr.puts("#{b.shift}: #{e.message} (#{e.class})")
@stderr.puts(b.map{|s| "\tfrom #{s}"}.join("\n"))
1
rescue SystemExit => e
e.status
ensure
# TODO: reset your app here, free up resources, etc.
# Examples:
# MyApp.logger.flush
# MyApp.logger.close
# MyApp.logger = nil
#
# MyApp.reset_singleton_instance_variables
# ...then we put the streams back.
$stderr = STDERR
$stdin = STDIN
$stdout = STDOUT
end
# Proxy our exit code back to the injected kernel.
@kernel.exit(exit_code)
end
end
end
# ...
require 'aruba/cucumber'
require 'aruba/in_process'
require 'mycli/runner'
Aruba::Processes::InProcess.main_class = MyCli::Runner
Aruba.process = Aruba::Processes::InProcess
# ...