RSpec-Command
rspec-command
is a helper module for using RSpec to test command-line
applications.
Quick Start
Add gem 'rspec-command'
to your Gemfile
and then configure it in your
spec_helper.rb
:
require 'rspec_command'
RSpec.configure do |config|
config.include RSpecCommand
end
You can then use the helpers in your specs:
require 'spec_helper'
describe 'myapp' do
command 'myapp --version'
its(:stdout) { is_expected.to include('1.0.0') }
end
command
The core helper is command
. It takes a command to run and sets it as the
subject for the example group. The command can be given as a string, array, or
block. If the command is given as an array, no shell processing is done before
running it. If the gem you are running inside has a Gemfile, all commands will
be run inside a bundle exec
. Each command is run in a new temporary directory
so the results of one test won't affect others.
command
also optionally takes a hash of options to pass through to
Mixlib::ShellOut.new
. Some common options include :input
to provide data on
stdin and :timeout
to change the execution timeout. The option allow_error
is not passed through to the underlying ShellOut
, but should be set to true
to avoid raising an exception if the command fails.
The subject will be set to a Mixlib::ShellOut
object so you can use
rspec-its
to check individual attributes:
describe 'myapp' do
command 'myapp --version'
its(:stdout) { is_expected.to include '1.0.0' }
its(:stderr) { is_expected.to eq '' }
its(:exitstatus) { is_expected.to eq 0 }
end
file
The file
method writes a file in to the temporary directory. You can provide
the file content as either a string or a block:
describe 'myapp' do
command 'myapp read data1.txt data2.txt'
file 'data1.txt', <<-EOH
a thing
EOH
file 'data2.txt' do
"another thing #{Time.now}"
end
its(:stdout) { is_expected.to include '2 files imported' }
end
fixture_file
The fixture_file
method copies a file or folder from a fixture to the
temporary directory:
describe 'myapp' do
command 'myapp read entries/'
fixture_file 'entries'
its(:stdout) { is_expected.to include '4 files imported' }
end
These fixtures are generally kept in spec/fixtures
but it can be customized
by redefining let(:fixture_root)
.
environment
The environment
method sets environment variables for subprocesses run by
command
:
describe 'myapp' do
command 'myapp show'
environment MYAPP_DEBUG: true
its(:stderr) { is_expected.to include '[debug]' }
end
match_fixture
The match_fixture
matcher lets you check the files created by a command
against a fixture:
describe 'myapp' do
command 'myapp write'
it { is_expected.to match_fixture 'write_data' }
end
capture_output
The capture_output
helper lets you redirect the stdout and stderr of a block
of code to strings. This includes any subprocesses or non-Ruby output. This can
help with integration testing of CLI code without the overhead of running a full
subprocess.
The returned object behaves like a string containing the stdout output, but has
stdout
, stderr
, and exitstatus
attributes to simulate the object used by
command
. exitstatus
will always be 0
.
describe 'myapp' do
subject do
capture_output do
MyApp::CLI.run('show')
end
end
its(:stdout) { is_expected.to include 'Entry:' }
end
RSpecCommand::Rake
The RSpecCommand::Rake
helper is an optional module you can include in your
example groups to test Rake tasks without the overhead of running Rake in a full
subprocess.
require 'rspec_command'
RSpec.configure do |config|
config.include RSpecCommand::Rake
end
describe 'rake myapp' do
rake_task 'myapp'
rakefile <<-EOH
require 'myapp'
task 'myapp' do
MyApp.rake_task
end
EOH
its(:stdout) { is_expected.to include 'Initialized new project' }
end
License
Copyright 2015, Noah Kantrowitz
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.