Merge pull request #9080 from sikachu/master-rails-test

Add `rails test` command to run the test suite
This commit is contained in:
Rafael Mendonça França 2013-03-11 08:15:54 -07:00
commit 90a97156e4
8 changed files with 591 additions and 132 deletions

@ -1,8 +1,7 @@
A Guide to Testing Rails Applications
=====================================
This guide covers built-in mechanisms offered by Rails to test your
application.
This guide covers built-in mechanisms in Rails for testing your application.
After reading this guide, you will know:
@ -38,11 +37,11 @@ Rails creates a `test` folder for you as soon as you create a Rails project usin
```bash
$ ls -F test
fixtures/ functional/ integration/ test_helper.rb unit/
controllers/ helpers/ mailers/ test_helper.rb
fixtures/ integration/ models/
```
The `unit` directory is meant to hold tests for your models, the `functional` directory is meant to hold tests for your controllers and the `integration` directory is meant to hold tests that involve any number of controllers interacting.
The `models` directory is meant to hold tests for your models, the `controllers` directory is meant to hold tests for your controllers and the `integration` directory is meant to hold tests that involve any number of controllers interacting.
Fixtures are a way of organizing test data; they reside in the `fixtures` folder.
@ -140,10 +139,9 @@ The default test stub in `test/models/post_test.rb` looks like this:
require 'test_helper'
class PostTest < ActiveSupport::TestCase
# Replace this with your real tests.
test "the truth" do
assert true
end
# test "the truth" do
# assert true
# end
end
```
@ -224,34 +222,30 @@ TIP: You can see all these rake tasks and their descriptions by running `rake --
### Running Tests
Running a test is as simple as invoking the file containing the test cases through Ruby:
Running a test is as simple as invoking the file containing the test cases through `rails test` command.
```bash
$ ruby -Itest test/models/post_test.rb
Loaded suite models/post_test
Started
$ rails test test/models/post_test.rb
.
Finished in 0.023513 seconds.
1 tests, 1 assertions, 0 failures, 0 errors
Finished tests in 0.009262s, 107.9680 tests/s, 107.9680 assertions/s.
1 tests, 1 assertions, 0 failures, 0 errors, 0 skips
```
This will run all the test methods from the test case. Note that `test_helper.rb` is in the `test` directory, hence this directory needs to be added to the load path using the `-I` switch.
You can also run a particular test method from the test case by using the `-n` switch with the `test method name`.
You can also run a particular test method from the test case by running the test and using `-n` switch with the `test method name`.
```bash
$ ruby -Itest test/models/post_test.rb -n test_the_truth
Loaded suite models/post_test
Started
$ rails test test/models/post_test.rb -n test_the_truth
.
Finished in 0.023513 seconds.
1 tests, 1 assertions, 0 failures, 0 errors
Finished tests in 0.009064s, 110.3266 tests/s, 110.3266 assertions/s.
1 tests, 1 assertions, 0 failures, 0 errors, 0 skips
```
This will run all test methods from the test case. Note that `test_helper.rb` is in the `test` directory, hence this directory needs to be added to the load path using the `-I` switch.
The `.` (dot) above indicates a passing test. When a test fails you see an `F`; when a test throws an error you see an `E` in its place. The last line of the output is the summary.
To see how a test failure is reported, you can add a failing test to the `post_test.rb` test case.
@ -266,17 +260,16 @@ end
Let us run this newly added test.
```bash
$ ruby unit/post_test.rb -n test_should_not_save_post_without_title
Loaded suite -e
Started
$ rails test test/models/post_test.rb -n test_should_not_save_post_without_title
F
Finished in 0.102072 seconds.
Finished tests in 0.044632s, 22.4054 tests/s, 22.4054 assertions/s.
1) Failure:
test_should_not_save_post_without_title(PostTest) [/test/models/post_test.rb:6]:
<false> is not true.
test_should_not_save_post_without_title(PostTest) [test/models/post_test.rb:6]:
Failed assertion, no message given.
1 tests, 1 assertions, 1 failures, 0 errors
1 tests, 1 assertions, 1 failures, 0 errors, 0 skips
```
In the output, `F` denotes a failure. You can see the corresponding trace shown under `1)` along with the name of the failing test. The next few lines contain the stack trace followed by a message which mentions the actual value and the expected value by the assertion. The default assertion messages provide just enough information to help pinpoint the error. To make the assertion failure message more readable, every assertion provides an optional message parameter, as shown here:
@ -292,9 +285,8 @@ Running this test shows the friendlier assertion message:
```bash
1) Failure:
test_should_not_save_post_without_title(PostTest) [/test/models/post_test.rb:6]:
Saved the post without a title.
<false> is not true.
test_should_not_save_post_without_title(PostTest) [test/models/post_test.rb:6]:
Saved the post without a title
```
Now to get this test to pass we can add a model level validation for the _title_ field.
@ -308,13 +300,12 @@ end
Now the test should pass. Let us verify by running the test again:
```bash
$ ruby unit/post_test.rb -n test_should_not_save_post_without_title
Loaded suite unit/post_test
Started
$ rails test test/models/post_test.rb -n test_should_not_save_post_without_title
.
Finished in 0.193608 seconds.
1 tests, 1 assertions, 0 failures, 0 errors
Finished tests in 0.047721s, 20.9551 tests/s, 20.9551 assertions/s.
1 tests, 1 assertions, 0 failures, 0 errors, 0 skips
```
Now, if you noticed, we first wrote a test which fails for a desired functionality, then we wrote some code which adds the functionality and finally we ensured that our test passes. This approach to software development is referred to as _Test-Driven Development_ (TDD).
@ -334,18 +325,17 @@ end
Now you can see even more output in the console from running the tests:
```bash
$ ruby unit/post_test.rb -n test_should_report_error
Loaded suite -e
Started
$ rails test test/models/post_test.rb -n test_should_report_error
E
Finished in 0.082603 seconds.
Finished tests in 0.030974s, 32.2851 tests/s, 0.0000 assertions/s.
1) Error:
test_should_report_error(PostTest):
NameError: undefined local variable or method `some_undefined_variable' for #<PostTest:0x249d354>
/test/models/post_test.rb:6:in `test_should_report_error'
NameError: undefined local variable or method `some_undefined_variable' for #<PostTest:0x007fe32e24afe0>
test/models/post_test.rb:10:in `block in <class:PostTest>'
1 tests, 0 assertions, 0 failures, 1 errors
1 tests, 0 assertions, 0 failures, 1 errors, 0 skips
```
Notice the 'E' in the output. It denotes a test with error.
@ -642,12 +632,9 @@ Here's what a freshly-generated integration test looks like:
require 'test_helper'
class UserFlowsTest < ActionDispatch::IntegrationTest
fixtures :all
# Replace this with your real tests.
test "the truth" do
assert true
end
# test "the truth" do
# assert true
# end
end
```
@ -755,23 +742,28 @@ end
Rake Tasks for Running your Tests
---------------------------------
You don't need to set up and run your tests by hand on a test-by-test basis. Rails comes with a number of rake tasks to help in testing. The table below lists all rake tasks that come along in the default Rakefile when you initiate a Rails project.
You don't need to set up and run your tests by hand on a test-by-test basis. Rails comes with a number of commands to help in testing. The table below lists all commands that come along in the default Rakefile when you initiate a Rails project.
| Tasks | Description |
| ------------------------------- | ----------- |
| `rake test` | Runs all unit, functional and integration tests. You can also simply run `rake` as the _test_ target is the default.|
| `rake test:controllers` | Runs all the controller tests from `test/controllers`|
| `rake test:functionals` | Runs all the functional tests from `test/controllers`, `test/mailers`, and `test/functional`|
| `rake test:helpers` | Runs all the helper tests from `test/helpers`|
| `rake test:integration` | Runs all the integration tests from `test/integration`|
| `rake test:mailers` | Runs all the mailer tests from `test/mailers`|
| `rake test:models` | Runs all the model tests from `test/models`|
| `rake test:recent` | Tests recent changes|
| `rake test:uncommitted` | Runs all the tests which are uncommitted. Supports Subversion and Git|
| `rake test:units` | Runs all the unit tests from `test/models`, `test/helpers`, and `test/unit`|
| Tasks | Description |
| ------------------------ | ----------- |
| `rails test` | Runs all unit, functional and integration tests. You can also simply run `rails test` as Rails will run all the tests by default|
| `rails test controllers` | Runs all the controller tests from `test/controllers`|
| `rails test functionals` | Runs all the functional tests from `test/controllers`, `test/mailers`, and `test/functional`|
| `rails test helpers` | Runs all the helper tests from `test/helpers`|
| `rails test integration` | Runs all the integration tests from `test/integration`|
| `rails test mailers` | Runs all the mailer tests from `test/mailers`|
| `rails test models` | Runs all the model tests from `test/models`|
| `rails test units` | Runs all the unit tests from `test/models`, `test/helpers`, and `test/unit`|
There're also some test commands which you can initiate by running rake tasks:
Brief Note About `Test::Unit`
| Tasks | Description |
| ------------------------ | ----------- |
| `rake test` | Runs all unit, functional and integration tests. You can also simply run `rake` as the _test_ target is the default.|
| `rake test:recent` | Tests recent changes|
| `rake test:uncommitted` | Runs all the tests which are uncommitted. Supports Subversion and Git|
Brief Note About `MiniTest`
-----------------------------
Ruby ships with a boat load of libraries. Ruby 1.8 provides `Test::Unit`, a framework for unit testing in Ruby. All the basic assertions discussed above are actually defined in `Test::Unit::Assertions`. The class `ActiveSupport::TestCase` which we have been using in our unit and functional tests extends `Test::Unit::TestCase`, allowing

@ -19,6 +19,38 @@
*Terence Lee*
* Rails now generates a `test/test_helper.rb` file with `fixtures :all` commented out by default,
since we don't want to force loading all fixtures for user when a single test is run. However,
fixtures are still going to be loaded automatically for test suites.
To force all fixtures to be create in your database, use `rails test -f` to run your test.
*Prem Sichanugrist*
* Add `rails test` command for running tests
To run all tests:
$ rails test
To run a test suite
$ rails test [models,helpers,units,controllers,mailers,...]
To run a selected test file(s):
$ rails test test/unit/foo_test.rb [test/unit/bar_test.rb ...]
To run a single test from a test file
$ rails test test/unit/foo_test.rb -n test_the_truth
For more information, see `rails test --help`.
This command will eventually replace `rake test:*` and `rake test` tasks
*Prem Sichanugrist and Chris Toomey*
* Add notice message for destroy action in scaffold generator.
*Rahul P. Chaudhari*

@ -5,6 +5,7 @@
"d" => "destroy",
"c" => "console",
"s" => "server",
"t" => "test",
"db" => "dbconsole",
"r" => "runner"
}
@ -16,6 +17,7 @@
generate Generate new code (short-cut alias: "g")
console Start the Rails console (short-cut alias: "c")
server Start the Rails server (short-cut alias: "s")
test Running the test file (short-cut alias: "t")
dbconsole Start a console for the database specified in config/database.yml
(short-cut alias: "db")
new Create a new Rails application. "rails new my_app" creates a
@ -78,6 +80,15 @@
server.start
end
when 'test'
$LOAD_PATH.unshift("./test")
require 'rails/commands/test_runner'
options = Rails::TestRunner.parse_arguments(ARGV)
ENV['RAILS_ENV'] ||= options[:environment] || 'test'
require APP_PATH
Rails::TestRunner.start(ARGV, options)
when 'dbconsole'
require 'rails/commands/dbconsole'
Rails::DBConsole.start

@ -0,0 +1,146 @@
require 'optparse'
require 'minitest/unit'
module Rails
# Handles all logic behind +rails test+ command.
class TestRunner
class << self
# Creates a new +TestRunner+ object with an array of test files to run
# based on the arguments. When no arguments are provided, it runs all test
# files. When a suite argument is provided, it runs only the test files in
# that suite. Otherwise, it runs the specified test file(s).
def start(files, options = {})
original_fixtures_options = options.delete(:fixtures)
options[:fixtures] = true
case files.first
when nil
new(Dir['test/**/*_test.rb'], options).run
when 'models'
new(Dir['test/models/**/*_test.rb'], options).run
when 'helpers'
new(Dir['test/helpers/**/*_test.rb'], options).run
when 'units'
new(Dir['test/{models,helpers,unit}/**/*_test.rb'], options).run
when 'controllers'
new(Dir['test/controllers/**/*_test.rb'], options).run
when 'mailers'
new(Dir['test/mailers/**/*_test.rb'], options).run
when 'functionals'
new(Dir['test/{controllers,mailers,functional}/**/*_test.rb'], options).run
when 'integration'
new(Dir['test/integration/**/*_test.rb'], options).run
else
options[:fixtures] = original_fixtures_options
new(files, options).run
end
end
# Parses arguments and sets them as option flags
def parse_arguments(arguments)
options = {}
orig_arguments = arguments.dup
OptionParser.new do |opts|
opts.banner = "Usage: rails test [path to test file(s) or test suite]"
opts.separator ""
opts.separator "Run a specific test file(s) or a test suite, under Rails'"
opts.separator "environment. If the file name(s) or suit name is omitted,"
opts.separator "Rails will run all tests."
opts.separator ""
opts.separator "Specific options:"
opts.on '-h', '--help', 'Display this help.' do
puts opts
exit
end
opts.on '-e', '--environment NAME', String, 'Specifies the environment to run this test under' do |e|
options[:environment] = e
end
opts.on '-f', '--fixtures', 'Load fixtures in test/fixtures/ before running the tests' do
options[:fixtures] = true
end
opts.on '-s', '--seed SEED', Integer, "Sets random seed" do |m|
options[:seed] = m.to_i
end
opts.on '-v', '--verbose', "Verbose. Show progress processing files." do
options[:verbose] = true
end
opts.on '-n', '--name PATTERN', "Filter test names on pattern (e.g. /foo/)" do |n|
options[:filter] = n
end
opts.separator ""
opts.separator "Support types of test suites:"
opts.separator "-------------------------------------------------------------"
opts.separator "* models (test/models/**/*)"
opts.separator "* helpers (test/helpers/**/*)"
opts.separator "* units (test/{models,helpers,unit}/**/*"
opts.separator "* controllers (test/controllers/**/*)"
opts.separator "* mailers (test/mailers/**/*)"
opts.separator "* functionals (test/{controllers,mailers,functional}/**/*)"
opts.separator "* integration (test/integration/**/*)"
opts.separator "-------------------------------------------------------------"
opts.parse! arguments
orig_arguments -= arguments
end
options
end
end
# Creates a new +TestRunner+ object with a list of test file paths.
def initialize(files, options)
@files = files
Rails.application.load_tasks
Rake::Task['db:test:load'].invoke
if options.delete(:fixtures)
if defined?(ActiveRecord::Base)
ActiveSupport::TestCase.send :include, ActiveRecord::TestFixtures
ActiveSupport::TestCase.fixture_path = "#{Rails.root}/test/fixtures/"
ActiveSupport::TestCase.fixtures :all
end
end
MiniTest::Unit.runner.options = options
MiniTest::Unit.output = SilentUntilSyncStream.new(MiniTest::Unit.output)
end
# Runs test files by evaluating each of them.
def run
@files.each { |filename| load(filename) }
end
# A null stream object which ignores everything until +sync+ has been set
# to true. This is only used to silence unnecessary output from MiniTest,
# as MiniTest calls +output.sync = true+ right before it outputs the first
# test result.
class SilentUntilSyncStream < File
# Creates a +SilentUntilSyncStream+ object by giving it a target stream
# object that will be assigned to +MiniTest::Unit.output+ after +sync+ is
# set to true.
def initialize(target_stream)
@target_stream = target_stream
super(File::NULL, 'w')
end
# Swaps +MiniTest::Unit.output+ to another stream when +sync+ is true.
def sync=(sync)
if sync
@target_stream.sync = true
MiniTest::Unit.output = @target_stream
end
super
end
end
end
end

@ -1,4 +1,4 @@
ENV["RAILS_ENV"] = "test"
ENV["RAILS_ENV"] ||= "test"
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'
@ -6,11 +6,12 @@ class ActiveSupport::TestCase
<% unless options[:skip_active_record] -%>
ActiveRecord::Migration.check_pending!
# Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
# Uncomment the `fixtures :all` line below to setup all fixtures in test/fixtures/*.yml
# for all tests in alphabetical order.
#
# Note: You'll currently still have to declare fixtures explicitly in integration tests
# -- they do not yet inherit this setting
fixtures :all
# fixtures :all
<% end -%>
# Add more helper methods to be used by all tests here...

@ -1,6 +1,7 @@
require 'rbconfig'
require 'rake/testtask'
require 'rails/test_unit/sub_test_task'
require 'active_support/deprecation'
TEST_CHANGES_SINCE = Time.now - 600
@ -47,7 +48,11 @@ task default: :test
desc 'Runs test:units, test:functionals, test:integration together'
task :test do
Rake::Task[ENV['TEST'] ? 'test:single' : 'test:run'].invoke
if ENV['TEST']
exec "bundle exec rails test #{ENV['TEST'].inspect}"
else
exec 'bundle exec rails test'
end
end
namespace :test do
@ -56,19 +61,8 @@ namespace :test do
end
task :run do
errors = %w(test:units test:functionals test:integration).collect do |task|
begin
Rake::Task[task].invoke
nil
rescue => e
{ task: task, exception: e }
end
end.compact
if errors.any?
puts errors.map { |e| "Errors running #{e[:task]}! #{e[:exception].inspect}" }.join("\n")
abort
end
ActiveSupport::Deprecation.warn "`rake test:run` is deprecated. Please use `rails test`."
exec 'bundle exec rails test'
end
# Inspired by: http://ngauthier.com/2012/02/quick-tests-with-bash.html
@ -83,7 +77,13 @@ namespace :test do
task :db => %w[db:test:prepare test:all]
end
Rake::TestTask.new(recent: "test:prepare") do |t|
# Display deprecation message
task :deprecated do
task_name = ARGV.first
ActiveSupport::Deprecation.warn "`rake #{ARGV.first}` is deprecated with no replacement."
end
Rake::TestTask.new(recent: ["test:deprecated", "test:prepare"]) do |t|
since = TEST_CHANGES_SINCE
touched = FileList['test/**/*_test.rb'].select { |path| File.mtime(path) > since } +
recent_tests('app/models/**/*.rb', 'test/models', since) +
@ -94,9 +94,9 @@ namespace :test do
t.libs << 'test'
t.test_files = touched.uniq
end
Rake::Task['test:recent'].comment = "Test recent changes"
Rake::Task['test:recent'].comment = "Deprecated; Test recent changes"
Rake::TestTask.new(uncommitted: "test:prepare") do |t|
Rake::TestTask.new(uncommitted: ["test:deprecated", "test:prepare"]) do |t|
def t.file_list
if File.directory?(".svn")
changed_since_checkin = silence_stderr { `svn status` }.split.map { |path| path.chomp[7 .. -1] }
@ -118,44 +118,20 @@ namespace :test do
t.libs << 'test'
end
Rake::Task['test:uncommitted'].comment = "Test changes since last checkin (only Subversion and Git)"
Rake::Task['test:uncommitted'].comment = "Deprecated; Test changes since last checkin (only Subversion and Git)"
Rake::TestTask.new(single: "test:prepare") do |t|
t.libs << "test"
desc "Deprecated; Please use `rails test \"#{ENV['TEST']}\"`"
task :single do
ActiveSupport::Deprecation.warn "`rake test:single` is deprecated. Please use `rails test \"#{ENV['TEST']}\"`."
exec "bundle exec rails test #{test_suit_name}"
end
Rails::SubTestTask.new(models: "test:prepare") do |t|
t.libs << "test"
t.pattern = 'test/models/**/*_test.rb'
end
[:models, :helpers, :units, :controllers, :functionals, :integration].each do |test_suit_name|
desc "Deprecated; Please use `rails test #{test_suit_name}`"
task test_suit_name do
ActiveSupport::Deprecation.warn "`rake test:#{test_suit_name}` is deprecated. Please use `rails test #{test_suit_name}`."
Rails::SubTestTask.new(helpers: "test:prepare") do |t|
t.libs << "test"
t.pattern = 'test/helpers/**/*_test.rb'
end
Rails::SubTestTask.new(units: "test:prepare") do |t|
t.libs << "test"
t.pattern = 'test/{models,helpers,unit}/**/*_test.rb'
end
Rails::SubTestTask.new(controllers: "test:prepare") do |t|
t.libs << "test"
t.pattern = 'test/controllers/**/*_test.rb'
end
Rails::SubTestTask.new(mailers: "test:prepare") do |t|
t.libs << "test"
t.pattern = 'test/mailers/**/*_test.rb'
end
Rails::SubTestTask.new(functionals: "test:prepare") do |t|
t.libs << "test"
t.pattern = 'test/{controllers,mailers,functional}/**/*_test.rb'
end
Rails::SubTestTask.new(integration: "test:prepare") do |t|
t.libs << "test"
t.pattern = 'test/integration/**/*_test.rb'
exec "bundle exec rails test #{test_suit_name}"
end
end
end

@ -91,19 +91,9 @@ def test_rake_test_error_output
raise 'models'
RUBY
app_file "test/controllers/one_controller_test.rb", <<-RUBY
raise 'controllers'
RUBY
app_file "test/integration/one_integration_test.rb", <<-RUBY
raise 'integration'
RUBY
silence_stderr do
output = Dir.chdir(app_path) { `rake test 2>&1` }
assert_match 'models', output
assert_match 'controllers', output
assert_match 'integration', output
end
end
@ -135,6 +125,19 @@ def test_rake_test_uncommitted_fails_with_no_scm
end
end
def test_rake_test_deprecation_messages
Dir.chdir(app_path){ `rails generate scaffold user name:string` }
Dir.chdir(app_path){ `rake db:migrate` }
%w(run recent uncommitted models helpers units controllers functionals integration).each do |test_suit_name|
output = Dir.chdir(app_path) { `rake test:#{test_suit_name} 2>&1` }
assert_match /DEPRECATION WARNING: `rake test:#{test_suit_name}` is deprecated/, output
end
assert_match /DEPRECATION WARNING: `rake test:single` is deprecated/,
Dir.chdir(app_path) { `rake test:single TEST=test/models/user_test.rb 2>&1` }
end
def test_rake_routes_calls_the_route_inspector
app_file "config/routes.rb", <<-RUBY
AppTemplate::Application.routes.draw do

@ -0,0 +1,298 @@
require 'isolation/abstract_unit'
require 'active_support/core_ext/string/strip'
module ApplicationTests
class TestRunnerTest < ActiveSupport::TestCase
include ActiveSupport::Testing::Isolation
def setup
build_app
create_schema
end
def teardown
teardown_app
end
def test_should_not_display_heading
create_test_file
run_test_command.tap do |output|
assert_no_match /Run options:/, output
assert_no_match /Running tests:/, output
end
end
def test_run_shortcut
create_test_file :models, 'foo'
output = Dir.chdir(app_path) { `bundle exec rails t test/models/foo_test.rb` }
assert_match /1 tests, 1 assertions, 0 failures/, output
end
def test_run_single_file
create_test_file :models, 'foo'
assert_match /1 tests, 1 assertions, 0 failures/, run_test_command("test/models/foo_test.rb")
end
def test_run_multiple_files
create_test_file :models, 'foo'
create_test_file :models, 'bar'
assert_match /2 tests, 2 assertions, 0 failures/, run_test_command("test/models/foo_test.rb test/models/bar_test.rb")
end
def test_run_file_with_syntax_error
app_file 'test/models/error_test.rb', <<-RUBY
require 'test_helper'
def; end
RUBY
error_stream = Tempfile.new('error')
redirect_stderr(error_stream) { run_test_command('test/models/error_test.rb') }
assert_match /SyntaxError/, error_stream.read
end
def test_invoke_rake_test_prepare
app_file "lib/tasks/test.rake", <<-RUBY
namespace :test do
task :prepare do
puts "Hello World"
end
end
RUBY
create_test_file
assert_match /Hello World/, run_test_command
end
def test_run_models
create_test_file :models, 'foo'
create_test_file :models, 'bar'
create_test_file :controllers, 'foobar_controller'
run_test_command("models").tap do |output|
assert_match /FooTest/, output
assert_match /BarTest/, output
assert_match /2 tests, 2 assertions, 0 failures/, output
end
end
def test_run_helpers
create_test_file :helpers, 'foo_helper'
create_test_file :helpers, 'bar_helper'
create_test_file :controllers, 'foobar_controller'
run_test_command('helpers').tap do |output|
assert_match /FooHelperTest/, output
assert_match /BarHelperTest/, output
assert_match /2 tests, 2 assertions, 0 failures/, output
end
end
def test_run_units
create_test_file :models, 'foo'
create_test_file :helpers, 'bar_helper'
create_test_file :unit, 'baz_unit'
create_test_file :controllers, 'foobar_controller'
run_test_command('units').tap do |output|
assert_match /FooTest/, output
assert_match /BarHelperTest/, output
assert_match /BazUnitTest/, output
assert_match /3 tests, 3 assertions, 0 failures/, output
end
end
def test_run_controllers
create_test_file :controllers, 'foo_controller'
create_test_file :controllers, 'bar_controller'
create_test_file :models, 'foo'
run_test_command('controllers').tap do |output|
assert_match /FooControllerTest/, output
assert_match /BarControllerTest/, output
assert_match /2 tests, 2 assertions, 0 failures/, output
end
end
def test_run_mailers
create_test_file :mailers, 'foo_mailer'
create_test_file :mailers, 'bar_mailer'
create_test_file :models, 'foo'
run_test_command('mailers').tap do |output|
assert_match /FooMailerTest/, output
assert_match /BarMailerTest/, output
assert_match /2 tests, 2 assertions, 0 failures/, output
end
end
def test_run_functionals
create_test_file :mailers, 'foo_mailer'
create_test_file :controllers, 'bar_controller'
create_test_file :functional, 'baz_functional'
create_test_file :models, 'foo'
run_test_command('functionals').tap do |output|
assert_match /FooMailerTest/, output
assert_match /BarControllerTest/, output
assert_match /BazFunctionalTest/, output
assert_match /3 tests, 3 assertions, 0 failures/, output
end
end
def test_run_integration
create_test_file :integration, 'foo_integration'
create_test_file :models, 'foo'
run_test_command('integration').tap do |output|
assert_match /FooIntegration/, output
assert_match /1 tests, 1 assertions, 0 failures/, output
end
end
def test_run_all_suites
suites = [:models, :helpers, :unit, :controllers, :mailers, :functional, :integration]
suites.each { |suite| create_test_file suite, "foo_#{suite}" }
run_test_command('') .tap do |output|
suites.each { |suite| assert_match /Foo#{suite.to_s.camelize}Test/, output }
assert_match /7 tests, 7 assertions, 0 failures/, output
end
end
def test_run_named_test
app_file 'test/unit/chu_2_koi_test.rb', <<-RUBY
require 'test_helper'
class Chu2KoiTest < ActiveSupport::TestCase
def test_rikka
puts 'Rikka'
end
def test_sanae
puts 'Sanae'
end
end
RUBY
run_test_command('test/unit/chu_2_koi_test.rb -n test_rikka').tap do |output|
assert_match /Rikka/, output
assert_no_match /Sanae/, output
end
end
def test_not_load_fixtures_when_running_single_test
create_model_with_fixture
create_fixture_test :models, 'user'
assert_match /0 users/, run_test_command('test/models/user_test.rb')
assert_match /3 users/, run_test_command('test/models/user_test.rb -f')
end
def test_load_fixtures_when_running_test_suites
create_model_with_fixture
suites = [:models, :helpers, [:units, :unit], :controllers, :mailers,
[:functionals, :functional], :integration]
suites.each do |suite, directory|
directory ||= suite
create_fixture_test directory
assert_match /3 users/, run_test_command(suite)
Dir.chdir(app_path) { FileUtils.rm_f "test/#{directory}" }
end
end
def test_run_different_environment_using_env_var
app_file 'test/unit/env_test.rb', <<-RUBY
require 'test_helper'
class EnvTest < ActiveSupport::TestCase
def test_env
puts Rails.env
end
end
RUBY
assert_match /development/, Dir.chdir(app_path) { `RAILS_ENV=development bundle exec rails test test/unit/env_test.rb` }
end
def test_run_different_environment_using_e_tag
app_file 'test/unit/env_test.rb', <<-RUBY
require 'test_helper'
class EnvTest < ActiveSupport::TestCase
def test_env
puts Rails.env
end
end
RUBY
assert_match /development/, run_test_command('-e development test/unit/env_test.rb')
end
def test_generated_scaffold_works_with_rails_test
create_scaffold
assert_match /0 failures, 0 errors, 0 skips/, run_test_command('')
end
private
def run_test_command(arguments = 'test/unit/test_test.rb')
Dir.chdir(app_path) { `bundle exec rails test #{arguments}` }
end
def create_model_with_fixture
script 'generate model user name:string'
app_file 'test/fixtures/users.yml', <<-YAML.strip_heredoc
vampire:
id: 1
name: Koyomi Araragi
crab:
id: 2
name: Senjougahara Hitagi
cat:
id: 3
name: Tsubasa Hanekawa
YAML
run_migration
end
def create_fixture_test(path = :unit, name = 'test')
app_file "test/#{path}/#{name}_test.rb", <<-RUBY
require 'test_helper'
class #{name.camelize}Test < ActiveSupport::TestCase
def test_fixture
puts "\#{User.count} users (\#{__FILE__})"
end
end
RUBY
end
def create_schema
app_file 'db/schema.rb', ''
end
def redirect_stderr(target_stream)
previous_stderr = STDERR.dup
$stderr.reopen(target_stream)
yield
target_stream.rewind
ensure
$stderr = previous_stderr
end
def create_test_file(path = :unit, name = 'test')
app_file "test/#{path}/#{name}_test.rb", <<-RUBY
require 'test_helper'
class #{name.camelize}Test < ActiveSupport::TestCase
def test_truth
puts "#{name.camelize}Test"
assert true
end
end
RUBY
end
def create_scaffold
script 'generate scaffold user name:string'
Dir.chdir(app_path) { File.exist?('app/models/user.rb') }
run_migration
end
def run_migration
Dir.chdir(app_path) { `bundle exec rake db:migrate` }
end
end
end