Git Product home page Git Product logo

rspec-command's Introduction

RSpec-Command

Build Status Gem Version Coverage Gemnasium License

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.

rspec-command's People

Contributors

coderanger avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

rspec-command's Issues

RSpecCommand::command runs the command again for every example

Consider a simple program called iterator, which each time it's called it will increment its value by 1 and output the number:

describe 'iterator' do
  command 'iterator' 

  its(:stdout) { is_expected.to eq '1' }
  its(:stderr) { is_expected.to eq '' }
end

Tests pass.

But if I reset the iterator and run the examples in a different order:

describe 'iterator' do
  command 'iterator' 

  its(:stderr) { is_expected.to eq '' }
  its(:stdout) { is_expected.to eq '1' }
end

Tests fail, because iterator has actually been called each time an example was run. subject[:stdout] is 2 by the time it gets to line

  its(:stdout) { is_expected.to eq '1' }

Instead of running the command again for every command. We should run the command once and save the output for all examples within a describe block.

Is there any way to load symlinks running rspec-command?

Hi, I'm trying to use rspec-command as a higher level integration test for non-ruby command line app. I'd like to define my specs using rspec and have it run say a swift or python command line app when the specs are executed. It seems like rspec-command isn't aware of symlinks in the directory where I run it. Is there a way to have those symlinks be linked?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.