Weird error when trying to test method with argument in Mocha. Is it a bug or is it me? - ruby

It's rather hard to find any documentation on Mocha, so I'm afraid I'm totally at sea here. I have found a problem with stubbing methods that pass arguments. So for instance if I set up a class like this:
class Red
def gets(*args)
#input.gets(*args)
end
def puts(*args)
#output.puts(*args)
end
def initialize
#input = $stdin
#output = $stdout
end
private
def first_method
input = gets.chomp
if input == "test"
second_method(input)
end
end
def second_method(value)
puts value
second_method(value)
end
end
Yes it's contrived, but it's a simplification of the idea that you may have a method that you don't want called in the test.
So I might write a test such as:
setup do
#project = Red.new
#project.instance_variable_set(:#input, StringIO.new("test\n"))
#project.stubs(:second_method)
end
should "pass input value to second_method" do
#project.expects(:second_method).with("test").once
#project.instance_eval {first_method}
end
Now I would expect this to pass. But instead I get this rather arcane error message:
Errno::ENOENT: No such file or directory - getcwd
/Users/i0n/.rvm/gems/ruby-1.9.2-head/gems/mocha-0.9.8/lib/mocha/backtrace_filter.rb:12:in `expand_path'
/Users/i0n/.rvm/gems/ruby-1.9.2-head/gems/mocha-0.9.8/lib/mocha/backtrace_filter.rb:12:in `block in filtered'
/Users/i0n/.rvm/gems/ruby-1.9.2-head/gems/mocha-0.9.8/lib/mocha/backtrace_filter.rb:12:in `reject'
/Users/i0n/.rvm/gems/ruby-1.9.2-head/gems/mocha-0.9.8/lib/mocha/backtrace_filter.rb:12:in `filtered'
/Users/i0n/.rvm/gems/ruby-1.9.2-head/gems/mocha-0.9.8/lib/mocha/expectation_error.rb:10:in `initialize'
/Users/i0n/.rvm/gems/ruby-1.9.2-head/gems/mocha-0.9.8/lib/mocha/mockery.rb:53:in `new'
/Users/i0n/.rvm/gems/ruby-1.9.2-head/gems/mocha-0.9.8/lib/mocha/mockery.rb:53:in `verify'
/Users/i0n/.rvm/gems/ruby-1.9.2-head/gems/mocha-0.9.8/lib/mocha/api.rb:156:in `mocha_verify'
/Users/i0n/.rvm/gems/ruby-1.9.2-head/gems/mocha-0.9.8/lib/mocha/integration/mini_test/version_131_and_above.rb:27:in `run'
This means absolutely nothing to me, other than something deep in Mochas bowels has just gone clang. If I write the same sort of test without an argument passing to the second method I get no problem. Am I missing something?

I think it must be something in shoulda causing the problem. I use test/unit, and everything appears to be OK.
require 'rubygems'
require "test/unit"
require 'mocha'
require File.dirname(__FILE__) + '/../src/red'
class RedTest < Test::Unit::TestCase
def setup
#project = Red.new
#project.instance_variable_set(:#input, StringIO.new("test\n"))
#project.stubs(:second_method)
end
def test_description_of_thing_being_tested
#project.expects(:second_method).with("test").once
#project.instance_eval {first_method}
end
end
gives the following output:
stephen#iolanta:~/tmp/red/test # ruby red_test.rb
Loaded suite red_test
Started
.
Finished in 0.000679 seconds.
1 tests, 1 assertions, 0 failures, 0 errors
stephen#iolanta:~/tmp/red/test #

Sorry - I've only just seen this. It's better to submit bug reports to us in Lighthouse. What documentation have you found? Have you seen the RDoc on Rubyforge? What sort of documentation were you looking for that you did not find?
I've been unable to reproduce your bug. What version of Ruby, Rubygems, Shoulda & Mocha were you using?
You can see the results of me running your test in this Gist.

Related

Use "vanilla" assert in Rspec?

How can someone use vanilla assert in Rspec?
require 'rspec'
describe MyTest do
it 'tests that number 1 equals 1' do
assert 1 == 1
end
end
The error I get:
undefined method `assert' for
#<RSpec::ExampleGroups::Metadata::LoadFile:0x00000002b232a0>
Notice that I don't want to use assert_equal, eq, should, or other mumbo jumbo.
You can do this pretty easily:
require 'rspec/core'
require 'test/unit'
describe 'MyTest' do
include Test::Unit::Assertions
it 'tests that number 1 equals 1' do
assert 1 == 2
end
end
(if you want to be able to run the tests by doing ruby foo.rb then you'll need to require rspec/autorun too). This pulls in all of those assertions. If you really don't want any extra assertions, just define your own assert method that raises an exception when the test should fail.
Conversely you can easily use rspec's expectation syntax outside of rspec by requiring rspec/expectations - rspec3 is designed to be modular.
Configure RSpec to use MiniTest
RSpec.configure do |rspec|
rspec.expect_with :stdlib
end
Then you can use all the asserts offered by MiniTest from the standard library.
...or Wrong
Alternatively, you can use Wrong if you like asserts with a block:
require 'wrong'
RSpec.configure do |rspec|
rspec.expect_with Wrong
end
describe Set do
specify "adding using the << operator" do
set = Set.new
set << 3 << 4
assert { set.include?(3) }
end
Inspired by this blog article on RSpec.info.

Can't understand why I'm getting a `initialize': uninitialized constant Controller::View (NameError)

I'm trying to understand why I'm getting this error and I suspect it's because I have my Controller class and View class in two separate Ruby files. I was told that using require_relative 'filename' should reference all the code from one file into another, but I seem to be missing something. Okay here goes,
In controller.rb file, I have
require_relative 'view'
require_relative 'deck_model'
require_relative 'flashcard_model'
class Controller
def initialize
#deckofcards = Deck.new
#welcome = View.new.welcome
#player_guess = View.new.get_user_guess
#success_view = View.new.success
#failure_view = View.new.failure
end
def run
#Logic to run the game
# #current_card
# #user_guess
puts "Let's see if this prints"
# pull_card_from_deck
end
end
In my view.rb file, I have,
require_relative 'controller'
class View
attr_accessor :userguess
def initialize (userguess = " ")
#userguess = userguess
end
def welcome
system ("clear")
puts "Welcome! Let's play a game."
puts "I'll give you a definition and you have to give me the term"
puts "Ready..."
end
def get_user_guess
#userguess = gets.chomp.downcase
end
def success
puts "Excellent! You got it."
end
def failure
puts "No, that's not quite right."
end
end
However when I run controller.rb, I get the following error,
/Users/sean/Projects/flash/source/controller.rb:11:in `initialize': uninitialized constant Controller::View (NameError)
from /Users/sean/Projects/flash/source/controller.rb:51:in `new'
from /Users/sean/Projects/flash/source/controller.rb:51:in `<top (required)>'
from /Users/sean/Projects/flash/source/view.rb:1:in `require_relative'
from /Users/sean/Projects/flash/source/view.rb:1:in `<top (required)>'
from controller.rb:1:in `require_relative'
from controller.rb:1:in `<main>'
Can anyone please help me figure this out.
You did not post your full code, but it sounds like this is an error caused by the circular dependencies you specified in your project. You have view.rb depending on controller.rb and controller.rb depending on view.rb. The Ruby interpreter will not execute these files simultaneously; it has to execute one and then execute the other.
It looks like it is executing controller.rb first, but it sees that view.rb is required, so it starts executing that. Then in view.rb it sees that controller.rb is required, so it starts executing controller.rb again. Then at some point in controller.rb, you must be creating a new instance of the Controller class. But we aren't done defining the View class yet, so View is undefined and you get an exception while trying to create that controller.
To fix this, you should consider not creating any Controller or View objects until both of the classes are fully loaded.
+1 to #DavidGrayson comment.
If my assumption is correct, your issue is with require_relative 'controller' in your view.rb file.
If you see, it looks like View is requiring Controller then Controller gets loaded which seems to be sending new somewhere to Controller which then sends new to View but it hasn't been completely required.

Ruby minitest assert_output syntax

I am new to minitest and still new to ruby and really tired of trying to google this question without result. I would be really grateful for help:
What is the exact syntax of assert_output in ruby minitest?
All I find on github or elsewhere seems to use parentheses. Yet, I get an error message when I don't use a block with assert_output, which makes sense as the definition of this method contains a yield statement.
But I cannot make it work, whatever I try.
testclass.rb
class TestClass
def output
puts 'hey'
end
end
test_test.rb
require 'minitest/spec'
require 'minitest/autorun'
require_relative 'testclass'
class TestTestClass < MiniTest::Unit::TestCase
def setup
#test = TestClass.new
end
def output_produces_output
assert_output( stdout = 'hey' ) { #test.output}
end
end
What I get is:
Finished tests in 0.000000s, NaN tests/s, NaN assertions
0 tests, 0 assertions, 0 failures, 0 errors, 0 skips
What am I doing wrong?
It must be something totally obvious, but I cannot figure it out.
Thanks for your help.
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

Why doesn't MiniTest::Spec have a wont_raise assertion?

Ruby's Test::Unit has assert_nothing_raised. Test::Unit has been replaced by MiniTest. Why don't MiniTest's assertions / expectations have anything parallel to this? For example you can expect must_raise but not wont_raise.
MiniTest does implement assert_nothing_raised in its Test::Unit compatibility layer, but in its own tests (MiniTest::Unit and MiniTest::Spec) it does not implement any test like this. The reason is, the programmer argues, that testing for nothing raised is not a test of anything; you never expect anything to be raised in a test, except when you are testing for an exception. If an unexpected (uncaught) exception occurs in the code for a test, you'll get an exception reported in good order by the test and you'll know you have a problem.
Example:
require 'minitest/autorun'
describe "something" do
it "does something" do
Ooops
end
end
Output:
Run options: --seed 41521
# Running tests:
E
Finished tests in 0.000729s, 1371.7421 tests/s, 0.0000 assertions/s.
1) Error:
test_0001_does_something(something):
NameError: uninitialized constant Ooops
untitled:5:in `block (2 levels) in <main>'
1 tests, 0 assertions, 0 failures, 1 errors, 0 skips
Which is exactly what you wanted to know. If you were expecting nothing to be raised, you didn't get it and you've been told so.
So, the argument here is: do not use assert_nothing_raised! It's just a meaningless crutch. See, for example:
https://github.com/seattlerb/minitest/issues/70
https://github.com/seattlerb/minitest/issues/159
http://blog.zenspider.com/blog/2012/01/assert_nothing_tested.html
On the other hand, clearly assert_nothing_raised corresponds to some intuition among users, since so many people expect a wont_raise to go with must_raise, etc. In particular one would like to focus an assertion on this, not merely a test. Luckily, MiniTest is extremely minimalist and flexible, so if you want to add your own routine, you can. So you can write a method that tests for no exception and returns a known outcome if there is no exception, and now you can assert for that known outcome.
For example (I'm not saying this is perfect, just showing the idea):
class TestMyRequire < MiniTest::Spec
def testForError # pass me a block and I'll tell you if it raised
yield
"ok"
rescue
$!
end
it "blends" do
testForError do
something_or_other
end.must_equal "ok"
end
end
The point is not that this is a good or bad idea but that it was never the responsibility of MiniTest to do it for you.
If you need it:
# test_helper.rb
module Minitest::Assertions
def assert_nothing_raised(*)
yield
end
end
And to use it:
def test_unknown_setter
assert_nothing_raised do
result.some_silly_column_name = 'value'
end
end
This bothered me enough to dig into the MiniTest sources and provide an implementation in my spec_helper.rb file:
module MiniTest
module Assertions
def refute_raises *exp
msg = "#{exp.pop}.\n" if String === exp.last
begin
yield
rescue MiniTest::Skip => e
return e if exp.include? MiniTest::Skip
raise e
rescue Exception => e
exp = exp.first if exp.size == 1
flunk "unexpected exception raised: #{e}"
end
end
end
module Expectations
infect_an_assertion :refute_raises, :wont_raise
end
end
Hope this proves helpful to someone else who also needs wont_raise. Cheers! :)

How do I effectively force Minitest to run my tests in order?

I know. This is discouraged. For reasons I won't get into, I need to run my tests in the order they are written. According to the documentation, if my test class (we'll call it TestClass) extends Minitest::Unit::TestCase, then I should be able to call the public method i_suck_and_my_tests_are_order_dependent! (Gee - do you think the guy who created Minitest had an opinion on that one?). Additionally, there is also the option of calling a method called test_order and specifying :alpha to override the default behavior of :random. Neither of these are working for me.
Here's an example:
class TestClass < Minitest::Unit::TestCase
#override random test run ordering
i_suck_and_my_tests_are_order_dependent!
def setup
...setup code
end
def teardown
...teardown code
end
def test_1
test_1 code....
assert(stuff to assert here, etc...)
puts 'test_1'
end
def test_2
test_2_code
assert(stuff to assert here, etc...)
puts 'test_2'
end
end
When I run this, I get:
undefined method `i_suck_and_my_tests_are_order_dependent!' for TestClass:Class (NoMethodError)
If I replace the i_suck method call with a method at the top a la:
def test_order
:alpha
end
My test runs, but I can tell from the puts for each method that things are still running in random order each time I run the tests.
Does anyone know what I'm doing wrong?
Thanks.
If you just add test_order: alpha to your test class, the tests will run in order:
class TestHomePage
def self.test_order
:alpha
end
def test_a
puts "a"
end
def test_b
puts "b"
end
end
Note that, as of minitest 5.10.1, the i_suck_and_my_tests_are_order_dependent! method/directive is completely nonfunctional in test suites using MiniTest::Spec syntax. The Minitest.test_order method is apparently not being called at all.
EDIT: This has been a known issue since Minitest 5.3.4: see seattlerb/minitest#514 for the blow-by-blow wailing and preening.
You and I aren't the ones who "suck". What's needed is a BDD specification tool for Ruby without the bloat of RSpec and without the frat-boy attitude and contempt for wider community practices of MiniTest. Does anyone have any pointers?
i_suck_and_my_tests_are_order_dependent! may be a later addition to minitest & not available as a Ruby core method. In that case, you'd want to force use of your gem version:
require 'rubygems'
gem 'minitest'
I think that the method *test_order* should be a class method and not a instance method like so:
# tests are order dependent
def self.test_order
:alpha
end
The best way to interfere in this chain may be to override a class method runnable_methods:
def self.runnable_methods
['run_first'] | super | ['run_last']
end
#Minitest version:
def self.runnable_methods
methods = methods_matching(/^test_/)
case self.test_order
when :random, :parallel then
max = methods.size
methods.sort.sort_by { rand max }
when :alpha, :sorted then
methods.sort
else
raise "Unknown test_order: #{self.test_order.inspect}"
end
end
You can reorder test any suitable way around. If you define your special ordered tests with
test 'some special ordered test' do
end
, don't forget to remove them from the results of super call.
In my example I need to be sure only in one particular test to run last, so I keep random order on whole suite and place 'run_last' at the end of it.

Resources