In RSpec I could create helper modules in /spec/support/...
module MyHelpers
def help1
puts "hi"
end
end
and include it in every spec like this:
RSpec.configure do |config|
config.include(MyHelpers)
end
and use it in my tests like this:
describe User do
it "does something" do
help1
end
end
How can I include a module into all MiniTest tests without repeating myself in every test?
From the Minitest README:
=== How to share code across test classes?
Use a module. That's exactly what they're for:
module UsefulStuff
def useful_method
# ...
end
end
describe Blah do
include UsefulStuff
def test_whatever
# useful_method available here
end
end
Just define the module in a file and use require to pull it in. For example, if 'UsefulStuff' is defined in test/support/useful_stuff.rb, you might have require 'support/useful_stuff' in either your individual test file.
UPDATE:
To clarify, in your existing test/test_helper.rb file or in a new test/test_helper.rb file you create, include the following:
Dir[Rails.root.join("test/support/**/*.rb")].each { |f| require f }
which will require all files in the test/support subdirectory.
Then, in each of your individual test files just add
require 'test_helper'
This is exactly analogous to RSpec, where you have a require 'spec_helper' line at the top of each spec file.
minitest does not provide a way to include or extend a module into every test class in the same way RSpec does.
Your best bet is going to be to re-open the test case class (differs, depending on the minitest version you're using) and include whatever modules you want there. You probably want to do this in either your test_helper or in a dedicated file that lets everyone else know you're monkey-patching minitest. Here are some examples:
For minitest ~> 4 (what you get with the Ruby Standard Library)
module MiniTest
class Unit
class TestCase
include MyHelpers
end
end
end
For minitest 5+
module Minitest
class Test
include MyHelperz
end
end
You can then use the included methods in your test:
class MyTest < Minitest::Test # or MiniTest::Unit::TestCase
def test_something
help1
# ...snip...
end
end
Hope this answers your question!
One thing I will do is create my own Test class inheriting from Minitest::Test. This allows me to do any sort of configuration on my base test class and keeping it isolated to my own project1.
# test_helper.rb
include 'helpers/my_useful_module'
module MyGem
class Test < Minitest::Test
include MyUsefulModule
end
end
# my_test.rb
include 'test_helper'
module MyGem
MyTest < Test
end
end
1 This is most likely unneeded, but I like keeping all my gem code isolated.
Related
In RSpec I could stub method like this:
allow(company).to receive(:foo){300}
How can I stub a method with ActiveSupport::TestCase?
I have a test like this.
class CompanyTest < ActiveSupport::TestCase
test 'foobar' do
company = companies(:base)
#company.stubs(:foo).returns(300)
assert_nil(company.calculate_bar)
end
end
Minitest comes with a stub method out of the box, in case you don't wanna use external tools:
require 'minitest/mock'
class CompanyTest < ActiveSupport::TestCase
test 'foobar' do
company = companies(:base)
Company.stub :foo, 300 do
assert_nil(company.calculate_bar)
end
end
end
Minitest has some limited functionality for mocks, but I'd suggest using the mocha gem for these kinds of stubs.
The syntax for Mocha is exactly what you have on the commented out line:
class CompanyTest < ActiveSupport::TestCase
test 'foobar' do
company = companies(:base)
company.stubs(:foo).returns(300)
assert_nil(company.calculate_bar)
end
end
Enhancing #Farrukh answer:
If you want to verify the arguments passed, like allow(company).to receive(:foo).with(some_args).and_return(300),
You can use assert_called_with.
# requiring may not be needed, depending on ActiveSupport version
require "active_support/testing/method_call_assertions.rb"
include ActiveSupport::Testing::MethodCallAssertions # so we can use `assert_called_with`
assert_called_with(company, :foo, some_args, returns: 300) do
assert_nil(company.calculate_bar)
end
I have a class that I'm trying to test that includes ActiveModel::Validations
module SomeModule
class SomeClass
include ActiveModel::Validations
end
end
I'm trying to test it without spec_helper to keep it fast, but a simple require 'activemodel' at the top of the spec doesn't work. I keep getting an uninitialized constant SomeModule::SomeClass::ActiveModel(NameError). for the spec file:
require 'activemodel'
describe SomeModule::SomeClass do
end
Any tips on solving this? Thanks in advance!
You will need to include active_model in your module/class file.
# /some_class.rb
require 'active_model'
module SomeModule
class SomeClass
include ActiveModel::Validations
end
end
Spec,
# /some_class_spec.rb
require './some_class'
describe SomeModule::SomeClass do
end
You'll want to change the paths to match your files. I doubt this will speed up your specs when run with other specs that include the whole Rails stack, but when run by itself this will be a little faster.
I've refactored part of my test suite to not load rails when performing tests. The code below is an example of a test file that loads only selection pieces of Rails. It also fakes the "project" class. My problem is that this faked project class ends up overriding the normal project class and all other tests that involve the project class now fail.
How do I un-override my project class after this test file runs?
require 'active_model'
require 'active_model/validations'
require 'active_record/callbacks'
require 'active_support/core_ext/string'
class Project
include ActiveModel::Validations
include ActiveRecord::Callbacks
def initialize(attributes = {})
#general_media = attributes[:general_media]
end
attr_accessor :general_media
end
require_relative '../../../app/models/project/media.rb'
UPDATE: I think this comes close to what I need, except that I'm getting an error about Project being an uninitialized constant. I must be instantiating this test class incorrectly.
require 'active_model'
require 'active_model/validations'
require 'active_record/callbacks'
require 'active_support/core_ext/string' #used for '.blank?' method
require_relative '../../../app/models/project/media.rb'
describe Project::Media do
before(:all) do
class Project
include ActiveModel::Validations
include ActiveRecord::Callbacks
def initialize(attributes = {})
#general_media = attributes[:general_media]
end
attr_accessor :general_media
end
end
after(:all) { Object.send(:remove_const, :Project) }
#then all the tests
You should be able to un-define a class with Module#remove_const.
Object.send(:remove_const, :Project)
Its a private method so you'll need to use send rather than a regular method call.
UPDATE:
Perhaps try the following:
require 'active_model'
require 'active_model/validations'
require 'active_record/callbacks'
require 'active_support/core_ext/string' #used for '.blank?' method
class Project
include ActiveModel::Validations
include ActiveRecord::Callbacks
def initialize(attributes = {})
#general_media = attributes[:general_media]
end
attr_accessor :general_media
end
require_relative '../../../app/models/project/media.rb'
describe Project::Media do
after(:all) { Object.send(:remove_const, :Project) }
...
You will need to declare the Project class before the describe block if the subject depends on it. Also assuming your Media model depends on it before you require that.
Later tests for the Project class will need to reload it, assuming they are separate tests you can just require your project model class in that test file if you want a minimal (fast) test, or via the normal spec_helper if you want to load the whole Rails application (slow).
As discussed in comments it might be easier to simply stub out the Project class rather than redefine it.
I'm starting the process of refactoring my tests to run without loading Rails. Most of my tests are still standard rspec tests that load rails. My problem is that in the test file below, I override one class that is used in many other test files. So even when these tests pass, the others fails. I'm looking to stub that Project class after getting a lot of advice here. (I would rather stub the project class in this file than to reload the project class in all the other test files that need it.)
Here's what I have now.
require 'active_model'
require 'active_model/validations'
require 'active_record/callbacks'
require 'active_support/core_ext/string' #used for '.blank?' method
class Project
attr_accessor :general_media
def initialize(attributes = {})
#general_media = attributes[:general_media]
end
include ActiveModel::Validations
include ActiveRecord::Callbacks
end
require_relative '../../../app/models/project/media.rb'
describe 'Project::Media' do
#then all the tests
I tried to to create a FakeProject class and to have Project::Media inherit from that by stubbing Project with FakeProject, but it didn't work. Here's what I've got.
require 'active_model'
require 'active_model/validations'
require 'active_record/callbacks'
require 'active_support/core_ext/string' #used for '.blank?' method
class FakeProject
attr_accessor :general_media
def initialize(attributes = {})
#general_media = attributes[:general_media]
end
include ActiveModel::Validations
include ActiveRecord::Callbacks
end
class Project; end
require_relative '../../../app/models/project/media.rb'
describe 'Project::Media' do
before(:all) { stub_constant!("Project", FakeProject) }
First off, I'm still overriding the project class and secondly, the stubbig isn't working. I still get an error about validations not working.
undefined method `validate' for Project::Media:Class (NoMethodError)
Any suggestions? My goal is to stub the Project class only for the tests in this media_spec.rb test file rather than override how the Project class behaves for all tests.
You can create a Fake class using the rspec syntax. Something like:
let(:fake_class) { Class.new }
stub_const("Project", fake_class)
And if you want to stub any method for that Project class, you can do like :
dummy_class = Project # the same name that you used above
# stub any method and return anything that you want to return
dummy_class.stub_chain(:any_method).and_return(anything)
Using rails and rspec it's easy to have rspec generate the necessary files for me when I'm using the rails generate command with models/views/controllers. But now I want to write specs for a module I wrote. The module is in /lib/my_module.rb so I created a spec in /spec/lib/my_module_spec.rb
The problem I'm having is that when I try to do rspec spec/ the file my_module_spec.rb is run but the reference to my module in lib/my_module.rb can't be found. What's the right way to do this?
Just FYI the my_module_spec.rb file does have require 'spec_helper' in it already
require 'spec_helper'
describe "my_module" do
it "first test"
result = MyModule.some_method # fails here because it can't find MyModule
end
end
You could try including the module and maybe wrapping it in an object
require 'spec_helper'
#EDIT according to
# http://stackoverflow.com/users/483040/jaydel
require "#{Rails.root}/lib/my_module.rb"
describe MyModule do
let(:wrapper){
class MyModuleWrapper
include MyModule
end
MyModuleWrapper.new
}
it "#some_method" do
wrapper.some_method.should == "something"
end
end
Does your module contain class methods or instance methods? Remember that only class methods will be available via
MyModule.some_method
meaning that some_method is defined as
def self.some_method
...
end
If your module contains instance methods, then use Jasper's solution above. Hope that clarifies.
Put the following in your config/application.rb file:
config.autoload_paths += %W(#{Rails.root}/lib)
I was just wrestling with the same problem, and the above worked for me. There's not really any reason you should have to jump through hoops to be able to access your lib/ files from RSpec and write tests for them.