I a have some code I'd like to refactor out of my step definitions and put them inside.. helpers?
Oh and please also say how to include them, I am really having a hard time finding any solid info on that.
Straight from the rspec documentation here: https://www.relishapp.com/rspec/rspec-core/docs/helper-methods/define-helper-methods-in-a-module#include-a-module-in-all-example-groups
Include a module in all example groups
Given a file named "include_module_spec.rb" with:
require './helpers'
RSpec.configure do |c|
c.include Helpers
end
RSpec.describe "an example group" do
it "has access to the helper methods defined in the module" do
expect(help).to be(:available)
end
end
When
I run rspec include_module_spec.rb
Then
the examples should all pass
You may also benefit from a a support/helpers folder Or equivalent which is covered pretty well here: How to include Rails Helpers on RSpec
My app does a lot with images. I use paperclip to attach them to models. I have tons of tests (Test::Unit) that involve creating images, these run pretty slowly.
I use FactoryGirl to create models in my tests. This is how I create image attachments:
factory :product_image_100_100 do
image File.new(File.join(::Rails.root.to_s, "/test/fixtures/images", "100_100.jpg"))
end
How can I fake the image upload or otherwise speed things up?
This snippet worked for me:
require 'test_helper'
class PhotoTest < ActiveSupport::TestCase
setup do
Paperclip::Attachment.any_instance.stubs(:post_process).returns(true)
end
# tests...
end
Upd. My current preference is to stub out ImageMagic globally, by adding the following to my test_helper.rb:
module Paperclip
def self.run(cmd, *)
case cmd
when "identify"
return "100x100"
when "convert"
return
else
super
end
end
end
(Adapted from here – btw, you may want to take a look at this article if you're interested in speeding up your tests)
I have a collection of parsers that differ significantly in logic, but have the exact same methods and outputs.
I have devised somewhat of a master Rake and I am curious if what I have come up with could lead to some unexpected or weird behavior.
Essentially my parse.rake looks something like:
require 'app/models/provider'
require 'config/environment.rb'
Provider.all.each do |provider|
require "lib/tasks/#{provider.name}.rb"
Kernel.const_get(provider.name).provider = provider
namespace provider.name do
task :provider_task do #Parse method
Kernel.const_get(provider.name).provider_task()
end
end
end
Since classes are constants in ruby, Kernel.const_get is what I used to access class methods from a varname. My classes look like (ABC.rb):
Class ABC
cattr_accessor :provider
def self.provider_task()
#Parse and add stuff to environment
end
end
With this setup, I can easily invoke rake ABC:provider_task to run a specific parser. Also the cattr_accessor allows me to easily refer to the actual provider model. Thoughts?
I have used this with no issues for a few weeks. After reviewing with some colleagues, I found a few who previously used a similar approach with no issues. Only potential danger is naming conflicts with your ruby classes.
I would like to know how to write unit tests for a module that is mixed into a couple of classes but don't quite know how to go about it:
Do I test the instance methods by writing tests in one of the test files for a class that includes them (doesn't seem right) or can you somehow keep the tests for the included methods in a separate file specific to the module?
The same question applies to the class methods.
Should I have a separate test file for each of the classes in the module like normal rails models do, or do they live in the general module test file, if that exists?
IMHO, you should be doing functional test coverage that will cover all uses of the module, and then test it in isolation in a unit test:
setup do
#object = Object.new
#object.extend(Greeter)
end
should "greet person" do
#object.stubs(:format).returns("Hello {{NAME}}")
assert_equal "Hello World", #object.greet("World")
end
should "greet person in pirate" do
#object.stubs(:format).returns("Avast {{NAME}} lad!")
assert_equal "Avast Jim lad!", #object.greet("Jim")
end
If your unit tests are good, you should be able to just smoke test the functionality in the modules it is mixed into.
Or…
Write a test helper, that asserts the correct behaviour, then use that against each class it's mixed in. Usage would be as follows:
setup do
#object = FooClass.new
end
should_act_as_greeter
If your unit tests are good, this can be a simple smoke test of the expected behavior, checking the right delegates are called etc.
Use inline classes (I am not doing any fancy flexmock or stubba/mocha usage just to show the point)
def test_should_callout_to_foo
m = Class.new do
include ModuleUnderTest
def foo
3
end
end.new
assert_equal 6, m.foo_multiplied_by_two
end
Any mocking/stubbing library out there should give you a cleaner way to do this. Also you can use structs:
instance = Struct.new(:foo).new
class<<instance
include ModuleUnderTest
end
instance.foo = 4
If I have a module that is being used in many places I have a unit test for it which does just that (slide a test object under the module methods and test if the module methods function properly on that object).
What I like to do is create a new host class and mix the module into it, something like this:
describe MyModule do
let(:host_class) { Class.new { include MyModule } }
let(:instance) { host_class.new }
describe '#instance_method' do
it 'does something' do
expect(instance.instance_method).to do_something
end
end
end
I try to keep my tests focused only on the contract for that particular class/module. If I've proven the module's behavior in a test class for that module (usually by including that module in a test class declared in the spec for that module) then I won't duplicate that test for a production class that uses that module. But if there's additional behavior that I want to test for the production class, or integration concerns, I'll write tests for the production class.
For instance I have a module called AttributeValidator that performs lightweight validations kind of similar to ActiveRecord. I write tests for the module's behavior in the module spec:
before(:each) do
#attribute_validator = TestAttributeValidator.new
end
describe "after set callbacks" do
it "should be invoked when an attribute is set" do
def #attribute_validator.after_set_attribute_one; end
#attribute_validator.should_receive(:after_set_attribute_one).once
#attribute_validator.attribute_one = "asdf"
end
end
class TestAttributeValidator
include AttributeValidator
validating_str_accessor [:attribute_one, /\d{2,5}/]
end
Now in a production class that includes the module, I won't re-assert that the callbacks are made, but I may assert that the included class has a certain validation set with a certain regular expression, something particular to that class, but not reproducing the tests I wrote for the module. In the spec for the production class, I want to guarantee that particular validations are set, but not that validations work in general. This is a kind of integration test, but one that doesn't repeat the same assertions I made for the module:
describe "ProductionClass validation" do
it "should return true if the attribute is valid" do
#production_class.attribute = #valid_attribute
#production_class.is_valid?.should be_true
end
it "should return false if the attribute is invalid" do
#production_class.attribute = #invalid_attribute
#production_class.is valid?.should be_false
end
end
There is some duplication here (as most integration tests will have), but the tests prove two different things to me. One set of tests prove the general behavior of the module, the other proves particular implementation concerns of a production class that uses that module. From these tests I know that the module will validate attributes and perform callbacks, and I know that my production class has a specific set of validations for specific criteria unique to the production class.
Hope that helps.
In minitest since each test is explicitly a class you can just include the module to the test and test the methods:
class MyModuleTest < Minitest::Test
include MyModule
def my_module_method_test
# Assert my method works
end
end
I would generally test the module in as much isolation as possible, essentially testing the methods, with just enough code, mocks and stubs to get it working.
I would then probably also have tests for the classes the modules is included in. I may not test every class, but would test enough of the classes to get good coverage and have insight into any issues that arise. These tests don't need to explicitly test the module, but would certainly test it's usage in particular scenarios.
Each set of tests would have its own file.
I'm adding more rspec testing to my app and would like to test a ScoringMethods module, which is in /lib/scoring_methods.rb. So I added a /spec/lib directory and added scoring_methods_spec.rb there. I required spec_helper and set up the describe block as so:
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe ScoringMethods do
describe "should have scorePublicContest method" do
methods = ScoringMethods.instance_methods
methods[0].should match(/scorePublicContest/)
end
end
Now methods[0] is a String and there is no problem matching the public method name with the regular expression. And the relative path to "spec_helper" is correct.
The problem is that the entire setup doesn't seem to use the rspec library.
Running the example yields:
./spec/lib/scoring_methods_spec.rb:7: undefined method `match' for Spec::Rails::Example::RailsExampleGroup::Subclass_1::Subclass_1:Class (NoMethodError)
...
The entire Expectation and Matcher support seems to be missing. To test my supposition, I changed a working helper spec by replacing "is_instance_of" to "is_foobar_of". That test simply fails and says "is_foobar_of" is not a method of the targeted object; that it, this entire Spec::Rails::Example... hierarchy isn't present.
I've tried using other matchers as well. I've tried "be_instance_of" and some others. It seems that I'm not including the rspec library properly.
Finally, ScoringMethods is a module, just the same way Helpers are modules. So I thought that it would be possible to test a module (as opposed to classes, such as Controllers and Models).
I'd greatly appreciate your thoughts on what I've done wrong. Perhaps there is a more effective way of testing library modules? Thanks!
You should include your test block in an "it" block. For example:
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe ScoringMethods do
describe "should have scorePublicContest method" do
it "should have a scorePublicContest method" do
methods = ScoringMethods.instance_methods
methods[0].should match(/scorePublicContest/)
end
end
end
You will find that the methods names returned aren't guaranteed to be in the order they exist in the file.
A model we often use when testing Modules is to include the module in either a class created for the test (inside the spec file) or included inside the spec itself.