Ruby minitest assert_output syntax
In order for your test method to run, the method name needs to start with test_
. Also, the way assert_output
works is that the block will write to stdout/stderr, and the arguments will be checked if they match stdout/stderr. The easiest way to check this IMO is to pass in a regexp. So this is how I would write that test:
class TestTestClass < MiniTest::Unit::TestCase
def setup
@test = TestClass.new
end
def test_output_produces_output
assert_output(/hey/) { @test.output}
end
end
MiniTest::Assertions returning false for test that should be returning true
MiniTest::Assertions assert
method call uses the syntax assert(test, msg = nil)
The reason your test is returning true is that is the message you chose to use. The assert_equal
method takes 2 values to compare. Also, instead of making the private method public, you can use the .send
method like this:
assert @purchase.send(:credit_card,@card_info).valid?
Also, change the setup to a function definition:
def setup
# setup logic
end
To make the output more verbose (capture the ActiveMerchant errors), try the following:
test "purchase" do
credit_card = @purchase.send(:credit_card, @card_info)
assert credit_card.valid?, "valid credit card"
puts credit_card.errors unless credit_card.errors.empty?
end
Reading rubyforge API I think the credit card type should be set to bogus in testing.
Customize minitest messages
Minitest has a verbose option that will show the test name and execution time for each test that's run. How you pass the -v
flag to Minitest will vary depending on how you're running your tests. See http://chriskottom.com/blog/2014/12/command-line-flags-for-minitest-in-the-raw/ for a sample of verbose output.
Another option would be using minitest-reporters with the SpecReporter by adding it to your Gemfile and putting this in your test helper:
require "minitest/reporters"
Minitest::Reporters.use! Minitest::Reporters::SpecReporter.new
See https://github.com/kern/minitest-reporters for more info.
Why doesn't Minitest's assert_raises work as expected in this case?
This isn't a problem with assert_raises
, that continues to work just fine. The issue you are having is that the exception you are raising within your Rails app is getting handled by your Rails app and not propagating out to your test. Calling get '/missing'
is raising the AbstractController::ActionNotFound
error, but then your app handles the error and returns an appropriate response (404 or 500) to the client (your test).
Okay, so how would you go about testing that your controller really did raise the error you are expecting? Normally you would just use an ActionController::TestCase
test to test your controllers. But, when you call an action on a controller that doesn't in ActionController::TestCase
you get a different error. So the following:
require "test_helper"
class TestControllerTest < ActionController::TestCase
def test_missing
assert_raises AbstractController::ActionNotFound do
get :missing
end
end
end
Produces the following output:
1) Failure:
TestControllerTest#test_missing [test/controllers/test_controller_test.rb:6]:
[AbstractController::ActionNotFound] exception expected, not
Class: <ActionController::UrlGenerationError>
Message: <"No route matches {:action=>\"missing\", :controller=>\"test\"}">
---Backtrace---
test/controllers/test_controller_test.rb:7:in `block in test_missing'
test/controllers/test_controller_test.rb:6:in `test_missing'
---------------
The reason is because ActionController::TestCase
is aware of the routes and won't allow calling an action that is not in the routes. But that is exactly what you are trying to test. And, I assume why you aren't using ActionController::TestCase
.
At this point I wonder if you aren't testing something you shouldn't. Perhaps you should allow Rails to do its job and trust that it behaves correctly. But hey, we've come this far, why not just go all the way and test what Rails tests anyway. Instead of making the call through the full Rails app, let's try calling the TestController
directly. If we create a new instance of the controller we can ask it to handle an action even if that action is not defined on the controller. But to do this we will have to dive deep into how ActionController works and make use of the AbstractController#process
method:
require "test_helper"
class TestControllerTest < Minitest::Test
def test_missing
assert_raises AbstractController::ActionNotFound do
TestController.new.process :missing
end
end
end
Now we are asking the controller to process an action that doesn't exist and testing that the controller behaves as expected. Yay?
Rails ActiveSupport: How to assert that an error is raised?
So unit testing isn't really in activesupport. Ruby comes with a typical xunit framework in the standard libs (Test::Unit in ruby 1.8.x, MiniTest in ruby 1.9), and the stuff in activesupport just adds some stuff to it.
If you are using Test::Unit/MiniTest
assert_raise(Exception) { whatever.merge }
if you are using rspec (unfortunately poorly documented, but way more popular)
lambda { whatever.merge }.should raise_error
If you want to check the raised Exception
:
exception = assert_raises(Exception) { whatever.merge }
assert_equal( "message", exception.message )
Related Topics
Rotate Bits Right Operation in Ruby
What's the Best Way to Return an Enumerator::Lazy When Your Class Doesn't Define #Each
Ssl_Connect Error When Accessing Shopify API with Rubygem
How to Create a Custom Method for the Rails Console
Fileutils.Mv Throwing Invalid Char \302 and \255 Exception
Rails 4 Many to Many Association Not Working
How to Capture a Part of a Screen Using Ruby on Windows
Ruby on Rails Active Admin Has_Many Changing Dropdown to Use a Different Column
Get Pry to Display Characters Like [äöüßÄÖÜß] (Utf-8 Encoding)? (Possibly Windows-Specific Issue)
Best Way to Find_Or_Create_By_Id But Update the Attributes If the Record Is Found
Handle Check Box Forms with an ':Has_Many :Through' Record Association
Net-Ssh and Remote Environment
Accessing the Child Instance in a Rabl Template
What's the Difference Between the Ruby Irb Prompt Modes
Routing Error No Route Matches [Get] "/Static_Pages/Home", Tutorial