Overwriting Rails Test Test::Unit::TestCase - ruby-on-rails

I am trying to overwrite/modify the teardown function of a Test::Unit::TestCase test.
During the teardown of the test (after it has finished), I want to do some extra stuff.
I tried this, but it doesn't work (keeps executing the original teardown):
module Test
module Unit
class TestCase
def teardown_modified
# do modifications
teardown_original
end
alias teardown_original teardown
alias teardown teardown_modified
end
end
end

Do you want it in one TestCase or in all?
If you need a change for all TestCases:
gem 'test-unit'
require 'test/unit'
module Test
module Unit
module Fixture
alias :run_teardown_old :run_teardown
def run_teardown
# do modifications
puts "In modified teardown"
run_teardown_old
end #def run_teardown
end #module Fixture
end #module Unit
end #module Test
class MyTest < Test::Unit::TestCase
def teardown
puts "In teardown"
end
def test_4()
assert_equal(2,1+1)
end
end

You might find that using alias_method_chain produces better results:
class Test::Unit::TestCase
def teardown_with_hacks
teardown_without_hacks
end
alias_method_chain :teardown, :hacks
end
This sets up a lot of the stuff for you automatically.

Related

Rspec Passes when all tests are run, but fail when individual tests are run

I noticed something strange in my rspec testing.
When I run all my rspec tests, my tests that rely on my require "plan_access_control" statement pass, for example, AController, BController, and CController all pass.
However, if I run BController_spec.rb separately, it fails. How do I get my tests to run in isolation to each other so they should fail? My assumption is that once the require gets loaded, it's loaded for all tests, but this should not happen.
# controllers/concerns/access_controllable.rb
module AccessControllable
extend ActiveSupport::Concern
require "plan_access_control"
def validation_object
#validation_object ||= PlanAccessControl::Validations.new(counts: 1)
end
end
#lib/plan_access_control.rb
module PlanAccessControl
autoload :Validations, "plan_access_control/validations"
end
# lib/plan_access_control/validations.rb
module PlanAccessControl
class Validations
def initialize(counts:)
self.counts = counts
end
end
end
# controller/a_controller.rb
class AController < ApplicationController
include AccessControllable
def new
#a = PlanAccessControl::Validations.new(counts: 1)
end
end
# controller/b_controller.rb
class BController < ApplicationController
def new
#b = PlanAccessControl::Validations.new(counts: 1)
end
end
# controller/c_controller.rb
class CController < ApplicationController
include AccessControllable
def new
#c = PlanAccessControl::Validations.new(counts: 1)
end
end

Rails ActiveSupport::TestCase - How do I dynamically define tests together with their helper methods?

I am building some abstraction into my Rails (5.2) tests as I want to run the same tests multiple times with different parameter sets.
I can successfully create a helper to generate test classes on the fly. This looks like the following, within my test_helper.rb:
class << self
def test_configs(configs: DEFAULT_CONFIGS, &block)
configs.each do |c|
Class.new(ActiveSupport::TestCase) { yield(c) }
end
end
end
I can use this helper in any given test file as follows:
require 'test_helper'
class SampleTest < ActiveSupport::TestCase
test_configs do |c|
test "#{c[:name]} - something is true" do
puts "#{c[:name]}" => # Correctly outputs c[:name]
end
end
end
"#{c[:name]}" is correctly interpolated for each iteration according to what "config" is passed from the helper. So far so good.
I am having though a problem creating some helper methods that also make use of the variable c, either within the test_configs method itself or within single test files.
None of the following works in giving a consistent match between the c variable that is passed to the test titles and what happens within the tests themselves:
# Approach 1
class SampleTest < ActiveSupport::TestCase
test_configs do |c|
def config_name
"#{c[:name]}" # => undefined local variable or method `c'
end
test "#{c[:name]} - something is true" do
puts "#{config_name}"
end
end
end
# Approach 2
class SampleTest < ActiveSupport::TestCase
test_configs do |c|
define_method("config_name") {
"#{c[:name]}"
}
test "#{c[:name]} - something is true" do
puts "#{config_name}" # => Uses only the last definition
end
end
end
# Approach 3
class << self
def test_configs(configs: DEFAULT_CONFIGS, &block)
configs.each do |c|
define_method "config_name" do # (same with def config_name)
"#{c[:name]}"
end
Class.new(ActiveSupport::TestCase) { yield(c) }
end
end
end
# => undefined local variable or method `config_name'
How do I get to correctly "inject" methods which make use of the passed variable?
The right approach was similar to the 3rd one in my question, but yield must be replaced by instance_eval in order for the code within the block to inherit the context of the new class I am creating:
# test_helper.rb
class ActiveSupport::TestCase
class << self
def test_configs(configs: DEFAULT_CONFIGS, &block)
configs.each do |c|
Class.new(ActiveSupport::TestCase) {
define_singleton_method "config_title" do
"#{c[:name]}".capitalize
end
define_method "config_name" do
"#{c[:name]}"
end
instance_eval(&block)
end
end
end
end
end
# sample_test.rb
require 'test_helper'
class SampleTest < ActiveSupport::TestCase
test_configs do
test "#{config_title} - something is true" do # => Correctly invokes the class method defined above
puts "#{config_name}" # => Correctly invokes the instance method defined above
end
end
end
As you can see, there is also a difference in that class methods must be defined in order to be used within test titles, while instance methods must be defined for being used within tests.
In case c must be passed to the block (e.g. for defining additional methods within the block itself), instance_exec should be the way to go: docs.

How can I stub in setup method with Minitest?

How can I use stub method in setup?
I only found the stub with block like this:
class FooTest < ActiveSupport::TestCase
test 'for_something' do
Foo.stub :some_method, 3 do
#assert_equal
end
end
end
But I want to stub for all tests. How can I stub it?
You can achieve that by overriding #run method in your test case:
class FooTest < ActiveSupport::TestCase
def run
Foo.stub :some_method, 3 do
super
end
end
test 'for_something' do
#assert_equal
end
end
It's a common way to introduce the code that needs to be executed "around" every test case.
I think this already answered here - https://stackoverflow.com/a/39081919/3102718
With gem mocha you can stub methods in setup or in test, e.g.:
require 'active_support'
require 'minitest/autorun'
require 'mocha/mini_test'
module Foo
end
class FooTest < ActiveSupport::TestCase
setup do
Foo.stubs(:some_method).returns(300)
end
test 'for_something' do
assert Foo.some_method == 300
end
end

Override model method in Rails

I have this in config/initializers/my_app_model.rb
module MyAppModel
def test
'test'
end
end
ActiveRecord::Base.send :include, MyAppModel
And in app/models/namespace/my_model.rb
class Namespace::MyModel < Namespace
def test
'changed!'
end
end
How can I make test to return changed!? It currently returns test.
From some posts I read, Rails loads models as they are asked, what I did was to make sure that model file was loaded just after initializer:
module MyAppModel
def test
'test'
end
end
ActiveRecord::Base.send :include, MyAppModel
require Rails.root.join 'app/models/namespace/my_model'

Accessing Methods in Ruby Module

I'm writing my first Ruby module and I have this:
/app/module/test_modules/test.rb
test.rb looks similar to:
module TestModules
module Test
def test
puts 'this is a test'
end
end
end
When I call the following from console, I get:
(main)> TestModule::Test.test
//NoMethodError: private method `test' called for TestModules::Test:Module
How do I make test() visible?
You are calling a class method, whereas you defined test as an instance method. You could call it the way you want if you used the module via include or extend. This article does a good job explaining.
module TestModules
module Test
def self.test
puts 'this is a test'
end
end
end
Also,
1)
module TestModules
module Test
def test
puts 'this is a test'
end
module_function :test
end
end
2)
module TestModules
module Test
extend self
def test
puts 'this is a test'
end
end
end
The way that you have defined your method, it is a method on an instance of Test - thus it would work if you did:
blah = TestModule::Test.new
blah.test
note - and do use it this way, you would need to define Test as a class not a module
If you want the function to work on the class itself, then you need to define it like so:
def self.test
....
end
And then you can do TestModules::Test.test
the test method you defined is instance method...try this
module TestModules
module Test
def self.test
puts 'this is a test'
end
end
end
now you can call the method by this TestModules::Test.test

Resources