Should I create helper methods in test files? - ruby-on-rails

Is it a good practice to create helper method in test file if this method is specific only to tests in this file?
For example, in:
test/integration/post_index_test.rb
among some tests i have defined helper method which is applicable only to tests in this file:
require 'test_helper'
class PostIndexTest < ActionDispatch::IntegrationTest
test 'some test' do
this_file_specific_helper_method
end
def only_this_file_specific_helper_method
# method body
end
end
Can I do this, or it should be avoided. If not, where should I put this method. In generic
test/test_helper.rb
file? Should I create a separate file? Or maybe there is something wrong with my design and I shouldn't have a need for this method at all?

Yes, you can use helper methods within your test files. I don't see why not. If the method performs a routine that you will be using many times within that specific test, using a private helper method would be the way to go.

Related

IntegrationTest with Mocha, stub HelperMethod (Ruby)

I got a helper method:
has_permission?
In a Module called:
module ApplicationHelper
Inside app/helpers.
I also have an IntegrationTest which includes it:
include ApplicationHelper
My Integration test calls one of my controllers via get request.
On call I want to test if my integration test arrives at a certain method.
On this way is has to pass a few of the methods, one of those being the
has_permission?
In order to make sure this method passes I wanted to stub it.
Object.any_instance.expects(:has_permission?).returns(false)
Doesn't work
ApplicationHelper.expects(:has_permission?).returns(false)
Doesn't work either because it's not a static method.
Is there a way I can stub the helpers non-static method within the test so I can make it return false in all cases?
The test:
test "test try to edit without permission" do
#curr = users(:me)
sign_in #curr
SellingController.expects(:validate).never
post enable_update_user_selling_path(id: #user, params: {user: {sell: "1"}})
end
Stumbled across this when trying to work out how to stub an ApplicationHelper method in an ActionDispatch::IntegrationTest in Rails 5; not sure if that's exactly what you're trying to achieve but I ended up doing something like this
MyController.view_context_class.any_instance.expects(:my_method).returns(true)
It looks as though since Rails 5, helper methods aren't simply mixed into the controller classes directly hence the view_context_class bit.
Seems to work, hopefully this will be helpful to someone!
Forgot to post how I ended up solving this:
SellingController.any_instance.stubs(:has_permission?).returns(false)

How do I access a helper method when I am running a test in rails?

I am writing a test for my email service, inside my email template file I call a helper method called: do_it, which is defined inside application_helper.rb
However, when i run my tests they fail because the helper methods are not imported, I get the following exception:
NoMethodError: undefined method `do_it'
Any idea / suggestions on how i can import helper methods into tests?
I am using:
require 'test_helper'
class NotifierTest < ActionMailer::TestCase
A Helper is just a module containing instance level methods. RSpec gives you a way to access this by default in the Helper specs that are automatically generated, by using helper.x within the describe block for the helper. If you're not using RSpec, there may be some other method provided by your test framework. Alternatively, you can mix the module into a class and test on an instance of the class.
Somewhere in the test setup:
class ApplicationHelperTest; include ApplicationHelper; end
#helper = ApplicationHelperTest.new
And in your test:
assert #helper.do_it
To better address your exact issue, what you need to do then is include the helper in the class that the method is being called on. For example, let's say the class is Mailer:
Mailer.send(:include, ApplicationHelper)

How can you include a mixin to make it available to all of your observers, models, controllers and RSpec?

I want to create a set of methods that are available to my models, controllers, views and RSpec.
Please note I don't want to test these methods in RSpec, I want them available to RSpec to use.
The reason I want to do this is that I have some helpers which override the Rails path_helper methods. Since those path helper methods get used directly in all of these different places I need to mix them in as such.
Hm, it is several ways to achieve your goal, one of them is to include your module with methods direct in ActiveRecord::Base, 'ApplicationController' and Rspec.
Not sure about RSpec (I don't quite sign with it's class/module structure) but you can do something like this in some initializer file:
class ActiveRecord::Base
include MyModuleWithAwesomeMethods
end
class ApplicationController
include MyModuleWithAwesomeMethods
end
etc. for other classes/modules
Hope it will help you.

Rails: How do I write tests for a ruby module?

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.

Adding rspec test for library module doesn't seem to pickup Expectations and Matchers

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.

Resources