How can I stub in setup method with Minitest? - ruby-on-rails

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

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 to include module for MiniTest

I have a class Company that include GrowthRate.
models/company.rb
class Company < ActiveRecord::Base
include GrowthRate
end
In the growth_rate.rb, I add some methods for Array.
models/company/growth_rate.rb
module Company::GrowthRate
extend ActiveSupport::Concern
end
module Company::GrowthRate::Array
def growth_rate
# calculate growth rate
end
end
class Array
include Company::GrowthRate::Array
end
And I want to test the method of Array by MiniTest.
test/models/company/growth_rate_test.rb
require 'test_helper'
class CompanyTest < ActiveSupport::TestCase
include Company::GrowthRate
test 'test for adjusted_growth_rate' do
array = [1, 0.9]
Array.stub :growth_rate, 1 do
# assert_equal
end
end
end
But the test ends up with a name error.
NameError: undefined method `growth_rate' for `Company::GrowthRate::Array'
How can I include the method for MiniTest?
test/test_helper.rb
ENV['RAILS_ENV'] ||= 'test'
require File.expand_path('../../config/environment', __FILE__)
require 'rails/test_help'
require 'minitest/mock'
class ActiveSupport::TestCase
# Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
fixtures :all
end
You'll want to use the ActiveSupport included block.
For your example, I imagine it can't find the method b/c you're not requiring that file anywhere.
module PolymorphicTest
extend ActiveSupport::Concern
included do
test 'some cool polymorphic test' do
assert private_helper_method
end
private
def private_helper_method
# do stuff
end
end
end
Minitest also doesn't autoload these, so you'll need to make sure they're included in a require in each test or in the test_helper.
If you need me to break this down more, please ask.
I think you have to move the models/company/growth_rate.rb into app/model/concerns folder with filename = 'growth_rate.rb'
then don't use Company class to prevent conflict class name
module GrowthRate
extend ActiveSupport::Concern
# ...
end
Now you can include it to your Company model
then create array.rb file in the config/initializers folder which contains
class Array
def growth_rate
# calculate growth rate
end
end
this file will loaded only once by rails, it's good to adding custom method to Array class if you want to
now you can remove include Company::GrowthRate from test/models/company/growth_rate_test.rb

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'

Overwriting Rails Test Test::Unit::TestCase

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.

Resources