Please consider the below code
class Execute
def self.inherited(klass)
puts "Class Inherited: #{klass}"
klass.run
end
def self.run
puts "Running Instance Methods"
instance_methods(false).each do |m|
if m.to_s.start_with?("test_")
puts "Executing Method: #{m}"
new.send(m)
end
end
end
end
puts "Before class definition"
class Raja < Execute
def test_1
puts 'test_1'
end
def test_2
puts 'test_2'
end
def test_3
puts 'test_3'
end
end
puts "After class definition"
I am currently making an attempt to access the test_1, test_2, and test_3 methods by instantiating an object from the parent class. Upon examination of the program, one may comprehend the actions I am performing. Nonetheless, the issue arises as the invocation of the instance_methods method returns an empty array, contrary to its expected behavior of providing the names of the instance methods, i.e., test_1, test_2, and test_3. I am at a loss as to why this discrepancy is occurring and would greatly appreciate any assistance in resolving this issue
Class#inherited is called at the moment of inheritance.
At this point no instance_methods (non-inherited instance methods since you used false) have been defined.
class Raja < Execute #inherited is called here
# methods are defined here
end
It would be similar to the following
class Raja;end
Raja.instance_methods(false) #=> []
class Raja
def test_1 = 'test1'
end
You could possibly look into Module#method_added instead however I am unclear on what the reasoning behind this code is so all I can do is answer the question of Why you are experiencing what you you are experiencing.
Update
Based on OP comments looking for an auto run mechanism similar to test-unit:
As a very simplified Example:
class Tracker
##runner = {}
def self.runner
##runner
end
def self.inherited(klass)
runner[klass] = []
end
def self.method_added(method_name)
runner[self] << method_name if method_name.match?(/test_/)
end
end
class Runner
def self.run
Tracker.runner.each do |klass,tests|
tests.each do |m|
klass.new.send(m)
end
end
end
end
# Run the Runner before the program exits
at_exit { Runner.run}
Then (foo.rb)
require 'runner_tracker'
class Foo < Tracker
def test_1
puts 'test_1'
end
def test_2
puts 'test_2'
end
def test_3
puts 'test_3'
end
end
Output
> ruby foo.rb
test_1
test_2
test_3
I'm writing RSpec unit tests for a CommandLineInterface class that I've created for my Directory object. The CommandLineInterface class uses this Directory object to print out a list of people in my Directory. Directory has a #sort_by(param) method that returns an array of strings. The order of the strings depends on the param passed to the #sort_by method (e.g., sort_by("gender"). What would be the correct way to mock out this Directory behavior in my CLI specs? Would I use an instance_double? I am not sure how to do this for a method that takes parameters, like sorting by gender.
I'm only using Ruby and RSpec. No Rails, ActiveRecord, etc. being used here.
Snippets from the class and method I want to mock out:
class Directory
def initialize(params)
#
end
def sort_by(param)
case param
when "gender" then #people.sort_by(&:gender)
when "name" then #people.sort_by(&:name)
else raise ArgumentError
end
end
end
It all depends on how your objects are collaborating.
Some information is lacking in your question:
How does CommandLineInterface use Directory? Does it create an instance by itself or does it receive one as an argument?
Are you testing class methods or instance methods? (Prefer instance methods)
Here's how you could do it if you pass in the dependent object:
require 'rspec/autorun'
class A
def initialize(b)
#b = b
end
def foo(thing)
#b.bar(thing)
end
end
RSpec.describe A do
describe '#foo' do
context 'when given qux' do
let(:b) { double('an instance of B') }
let(:a) { A.new(b) }
it 'calls b.bar with qux' do
expect(b).to receive(:bar).with('qux')
a.foo('qux')
end
end
end
end
If the class initializes the dependant object and it isn't important to know which instance got the message you can do this:
require 'rspec/autorun'
B = Class.new
class A
def initialize
#b = B.new
end
def foo(thing)
#b.bar(thing)
end
end
RSpec.describe A do
describe '#foo' do
context 'when given qux' do
let(:a) { A.new }
it 'calls b.bar with qux' do
expect_any_instance_of(B).to receive(:bar).with('qux')
a.foo('qux')
end
end
end
end
If you just want to stub out the return value and not test whether the exact message was received, you can use allow:
require 'rspec/autorun'
B = Class.new
class A
def initialize
#b = B.new
end
def foo(thing)
thing + #b.bar(thing)
end
end
RSpec.describe A do
describe '#foo' do
context 'when given qux' do
let(:a) { A.new }
it 'returns qux and b.bar' do
allow_any_instance_of(B).to receive(:bar).with('qux') { 'jabber' }
expect(a.foo('qux')).to eq('quxjabber')
end
end
end
end
When I run in the terminal "ruby game_test.rb" nothing happens, can someone explain me why?
Here is the game.rb:
class Game
attr_reader :number
def initialize(number)
#number = number
end
def return_number
number
end
def make_array
Array.new(number)
end
def fill_array
array = make_array
counter = 1
array.each do |element|
element = counter
counter += 1
end
array
end
end
and here is the test game_test.rb:
require_relative "game"
require "test/unit"
class GameTest < Test::Unit::TestCase
def fill_array
assert_equal(1, Game.new(50).fill_array)
end
end
A method must start with test_ for Test::Unit to think it is a test method and run it automatically, i.e.
class GameTest < Test::Unit::TestCase
def test_fill_array
assert_equal(1, Game.new(50).fill_array)
end
end
Without the prefix, it thinks your method is just a helper used during your tests.
Hi I try to make my first game in ruby :)
I have two files:
#"game.rb" with code:
class Game
attr_accessor :imie, :klasa, :honor
def initialize(start_scena)
#start = start_scena
end
def name()
puts "Some text"
exit(0)
end
end
and second file
#"game_engine.rb"
require_relative 'game.rb'
class Start
def initialize
#game = Game.new(:name)
end
def play()
next_scena = #start
while true
puts "\n---------"
scena = method(next_scena)
next_scena = scena.call()
end
end
end
go = Start.new()
go.play()
The question is, how can I call class Game.name method from Start.play() class. The game goes deeper, and insted of 'exit(0)' it returns :symbol of another method from "Game" class that should work.
Make start readable for the Game class. DO NOT call exit(0) in your code unless it's really necessary. Instead, use some conditions to make sure the program runs to the end of script.
#"game.rb" with code:
class Game
attr_accessor :imie, :klasa, :honor
attr_reader :start
def initialize(start_scena)
#start = start_scena
end
def name()
puts "Some text"
:round2
end
def round2
puts "round2"
nil
end
end
Use instance#method(...) to get a bounded method to that instance.
#"game_engine.rb"
require_relative 'game.rb'
class Start
def initialize
#game = Game.new(:name)
end
def play()
next_scene = #game.start
while next_scene
puts "\n---------"
scene = #game.method(next_scene)
next_scene = scene.call()
end
end
end
go = Start.new()
go.play()
I'm struggling with Test::Unit. When I think of unit tests, I think of one simple test per file. But in Ruby's framework, I must instead write:
class MyTest < Test::Unit::TestCase
def setup
end
def test_1
end
def test_1
end
end
But setup and teardown run for every invocation of a test_* method. This is exactly what I don't want. Rather, I want a setup method that runs just once for the whole class. But I can't seem to write my own initialize() without breaking TestCase's initialize.
Is that possible? Or am I making this hopelessly complicated?
As mentioned in Hal Fulton's book "The Ruby Way".
He overrides the self.suite method of Test::Unit which allows the test cases in a class to run as a suite.
def self.suite
mysuite = super
def mysuite.run(*args)
MyTest.startup()
super
MyTest.shutdown()
end
mysuite
end
Here is an example:
class MyTest < Test::Unit::TestCase
class << self
def startup
puts 'runs only once at start'
end
def shutdown
puts 'runs only once at end'
end
def suite
mysuite = super
def mysuite.run(*args)
MyTest.startup()
super
MyTest.shutdown()
end
mysuite
end
end
def setup
puts 'runs before each test'
end
def teardown
puts 'runs after each test'
end
def test_stuff
assert(true)
end
end
FINALLY, test-unit has this implemented! Woot!
If you are using v 2.5.2 or later, you can just use this:
Test::Unit.at_start do
# initialization stuff here
end
This will run once when you start your tests off. There are also callbacks which run at the beginning of each test case (startup), in addition to the ones that run before every test (setup).
http://test-unit.rubyforge.org/test-unit/en/Test/Unit.html#at_start-class_method
That's how it's supposed to work!
Each test should be completely isolated from the rest, so the setup and tear_down methods are executed once for every test-case. There are cases, however, when you might want more control over the execution flow. Then you can group the test-cases in suites.
In your case you could write something like the following:
require 'test/unit'
require 'test/unit/ui/console/testrunner'
class TestDecorator < Test::Unit::TestSuite
def initialize(test_case_class)
super
self << test_case_class.suite
end
def run(result, &progress_block)
setup_suite
begin
super(result, &progress_block)
ensure
tear_down_suite
end
end
end
class MyTestCase < Test::Unit::TestCase
def test_1
puts "test_1"
assert_equal(1, 1)
end
def test_2
puts "test_2"
assert_equal(2, 2)
end
end
class MySuite < TestDecorator
def setup_suite
puts "setup_suite"
end
def tear_down_suite
puts "tear_down_suite"
end
end
Test::Unit::UI::Console::TestRunner.run(MySuite.new(MyTestCase))
The TestDecorator defines a special suite which provides a setup and tear_down method which run only once before and after the running of the set of test-cases it contains.
The drawback of this is that you need to tell Test::Unit how to run the tests in the unit. In the event your unit contains many test-cases and you need a decorator for only one of them you'll need something like this:
require 'test/unit'
require 'test/unit/ui/console/testrunner'
class TestDecorator < Test::Unit::TestSuite
def initialize(test_case_class)
super
self << test_case_class.suite
end
def run(result, &progress_block)
setup_suite
begin
super(result, &progress_block)
ensure
tear_down_suite
end
end
end
class MyTestCase < Test::Unit::TestCase
def test_1
puts "test_1"
assert_equal(1, 1)
end
def test_2
puts "test_2"
assert_equal(2, 2)
end
end
class MySuite < TestDecorator
def setup_suite
puts "setup_suite"
end
def tear_down_suite
puts "tear_down_suite"
end
end
class AnotherTestCase < Test::Unit::TestCase
def test_a
puts "test_a"
assert_equal("a", "a")
end
end
class Tests
def self.suite
suite = Test::Unit::TestSuite.new
suite << MySuite.new(MyTestCase)
suite << AnotherTestCase.suite
suite
end
end
Test::Unit::UI::Console::TestRunner.run(Tests.suite)
The Test::Unit documentation documentation provides a good explanation on how suites work.
Well, I accomplished basically the same way in a really ugly and horrible fashion, but it was quicker. :) Once I realized that the tests are run alphabetically:
class MyTests < Test::Unit::TestCase
def test_AASetup # I have a few tests that start with "A", but I doubt any will start with "Aardvark" or "Aargh!"
#Run setup code
end
def MoreTests
end
def test_ZTeardown
#Run teardown code
end
It aint pretty, but it works :)
To solve this problem I used the setup construct, with only one test method followed. This one testmethod is calling all other tests.
For instance
class TC_001 << Test::Unit::TestCase
def setup
# do stuff once
end
def testSuite
falseArguments()
arguments()
end
def falseArguments
# do stuff
end
def arguments
# do stuff
end
end
I know this is quite an old post, but I had the issue (and had already written classes using Tes/unit) and ave answered using another method, so if it can help...
If you only need the equivalent of the startup function, you can use the class variables:
class MyTest < Test::Unit::TestCase
##cmptr = nil
def setup
if ##cmptr.nil?
##cmptr = 0
puts "runs at first test only"
##var_shared_between_fcs = "value"
end
puts 'runs before each test'
end
def test_stuff
assert(true)
end
end
I came across this exact problem and created a subclass of Test::Unit::TestCase for doing exactly what you describe.
Here's what I came up with. It provides it's own setup and teardown methods that count the number of methods in the class that begin with 'test'. On the first call to setup it calls global_setup and on the last call to teardown it calls global_teardown
class ImprovedUnitTestCase < Test::Unit::TestCase
cattr_accessor :expected_test_count
def self.global_setup; end
def self.global_teardown; end
def teardown
if((self.class.expected_test_count-=1) == 0)
self.class.global_teardown
end
end
def setup
cls = self.class
if(not cls.expected_test_count)
cls.expected_test_count = (cls.instance_methods.reject{|method| method[0..3] != 'test'}).length
cls.global_setup
end
end
end
Create your test cases like this:
class TestSomething < ImprovedUnitTestCase
def self.global_setup
puts 'global_setup is only run once at the beginning'
end
def self.global_teardown
puts 'global_teardown is only run once at the end'
end
def test_1
end
def test_2
end
end
The fault in this is that you can't provide your own per-test setup and teardown methods unless you use the setup :method_name class method (only available in Rails 2.X?) and if you have a test suite or something that only runs one of the test methods, then the global_teardown won't be called because it assumes that all the test methods will be run eventually.
Use the TestSuite as #romulo-a-ceccon described for special preparations for each test suite.
However I think it should be mentioned here that Unit tests are ment to run in total isolation. Thus the execution flow is setup-test-teardown which should guarantee that each test run undisturbed by anything the other tests did.
I created a mixin called SetupOnce. Here's an example of using it.
require 'test/unit'
require 'setuponce'
class MyTest < Test::Unit::TestCase
include SetupOnce
def self.setup_once
puts "doing one-time setup"
end
def self.teardown_once
puts "doing one-time teardown"
end
end
And here is the actual code; notice it requires another module available from the first link in the footnotes.
require 'mixin_class_methods' # see footnote 1
module SetupOnce
mixin_class_methods
define_class_methods do
def setup_once; end
def teardown_once; end
def suite
mySuite = super
def mySuite.run(*args)
#name.to_class.setup_once
super(*args)
#name.to_class.teardown_once
end
return mySuite
end
end
end
# See footnote 2
class String
def to_class
split('::').inject(Kernel) {
|scope, const_name|
scope.const_get(const_name)
}
end
end
Footnotes:
http://redcorundum.blogspot.com/2006/06/mixing-in-class-methods.html
http://infovore.org/archives/2006/08/02/getting-a-class-object-in-ruby-from-a-string-containing-that-classes-name/
+1 for the RSpec answer above by #orion-edwards. I would have commented on his answer, but I don't have enough reputation yet to comment on answers.
I use test/unit and RSpec a lot and I have to say ... the code that everyone has been posting is missing a very important feature of before(:all) which is: #instance variable support.
In RSpec, you can do:
describe 'Whatever' do
before :all do
#foo = 'foo'
end
# This will pass
it 'first' do
assert_equal 'foo', #foo
#foo = 'different'
assert_equal 'different', #foo
end
# This will pass, even though the previous test changed the
# value of #foo. This is because RSpec stores the values of
# all instance variables created by before(:all) and copies
# them into your test's scope before each test runs.
it 'second' do
assert_equal 'foo', #foo
#foo = 'different'
assert_equal 'different', #foo
end
end
The implementations of #startup and #shutdown above all focus on making sure that these methods only get called once for the entire TestCase class, but any instance variables used in these methods would be lost!
RSpec runs its before(:all) in its own instance of Object and all of the local variables are copied before each test is run.
To access any variables that are created during a global #startup method, you would need to either:
copy all of the instance variables created by #startup, like RSpec does
define your variables in #startup into a scope that you can access from your test methods, eg. ##class_variables or create class-level attr_accessors that provide access to the #instance_variables that you create inside of def self.startup
Just my $0.02!