I write a engine to add some helper methods just for learning.
module SharpAssets
class Engine < ::Rails::Engine
initializer "sharp_asssets.assets_precompile" do |app|
ActionView::Base.send(:include, SharpAssets::Helper)
end
end
module Helper
def hi_engine
"test"
end
end
end
and my test case is :
require 'test_helper'
class SharpAssetsTest < ActionView::TestCase
include SharpAssets::Helper
test "should work" do
assert_equal "test", hi_engine
end
end
I want to know is this way a good practice ?
And another question is why I can include SharpAssets::Helper in my test case ? I don't require any files from lib folder.
Related
There is my Observer code:
class ActivityObserver < ActiveRecord::Observer
observe PublicActivity::Activity
def after_create(activity)
if activity.trackable
Something.create(trackable: trackable)
end
end
end
My spec is
require 'spec_helper'
describe ActivityObserver do
describe '#after_create' do
it "should be triggered after an activity is created'" do
activity = create(:activity)
ActivityObserver.instance.should_receive(:after_create).with(activity)
end
end
end
But it did not pass
move and edit this line
ActivityObserver.instance.should_receive(:after_create)
above
activity = create(:activity)
you are calling create before telling Rspec to look for the after_create call, that's probably why its failing
To prevent removal of related records, I am applying the before_destroy callbacks approach on each model
I defined several related-records validation methods in a module, so that they can be shared to different models' before_destroy callbacks:
class Teacher < ActiveRecord::Base
include RelatedModels
before_destroy :has_courses
...
end
class Level < ActiveRecord::Base
include RelatedModels
before_destroy :has_courses
...
end
module RelatedModels
def has_courses
if self.courses.any?
self.errors[:base] << "You cannot delete this while associated courses exists"
return false
end
end
def has_reports
if self.reports.any?
self.errors[:base] << "You cannot delete this while associated reports exists"
return false
end
end
def has_students
if self.students.any?
self.errors[:base] << "You cannot delete this while associated students exists"
return false
end
end
...
end
But it doesn't looks very DRY
Any idea how to do it in a single method?
Meta-programming it's not among my skills
Thanks in advance
You might want to try an observer class
These are depreciated in Rails 4 (you have to use the rails-observers gem), but seem to be still part of the Rails 3 core
Observer Classes
"Listen" to specified actions in your model, and provide extended functionality. As stated by their documentation, they are particularly good for de-cluttering your models, allowing you to combine a lot of functionality into one central set of functions
Here's what you might want to do (please bare in mind I have only used these in Rails 4):
class RelatedObserver < ActiveRecord::Observer
observe :teachers, :school
def before_destroy(record)
associations = %w(teachers schools reports)
associations.each do |association|
if record.send(association).any?
self.errors[:base] << "You cannot delete this while associated #{association.pluralize} exists"
return false
end
end
end
end
Here's a good resource for you
I'm starting to attempt to incorporate more testing into my code, but I've hit a wall.
My model looks something like this
class Image < ActiveRecord:Base
before_create :do_something_general
before_update :do_something_on_update, :do_something_general
belongs_to :captureable, polymorphic: true
mount_uploader :image, SomeUploader
...
end
My rspec looks something like
describe SomeModel do
before :each do
#image = FactoryGirl.create(:image)
end
...
describe "moving image" do
context "change the parent of the image" do
it "moves" do
new_parent = FactoryGirl.create(:parent)
current_file_path = #image.image.file.path
#image.captureable = new_parent
#image.save!
#image.image.file.path.should_not == current_file_path
end
end
end
end
When I first create an Image, it will get stored in a file tree structure that depends on its parents. When a parent changes, the Image should be moved, and this is done with the before_update callback :do_something_on_update. My test should verify that when the Image has had its parent changed, it is located in a new location.
The problem is, when #image.save.should be_valid an except is returned because :do_something_general is run before :do_something_on_update (the order is important). It seems that the rspec thinks I'm creating a new object (using debugger I've checked that the object id doesn't change when modifying it), and thus runs before_create instead of before_update.
Edit: it seems that before_update is working, but only on callback methods that are in the class, but not in the module. In this case, :do_something_on_update is located in an included module.
End Edit
When I try this in the console in development mode, it works as expected.
Other things to note: I'm using Carrierwave for uploading (the image column is a carrierwave uploader) and when the :image factory is called, it also creates several parents and grandparent objects. Using Rspec 2.10, Rails 3.2.8, Ruby 1.9.3
Looking forward to your responses.
Thanks.
I would expect image.save.should be_valid to fail, because it's going to invoke image.save, which returns true or false, then it's going to invoke #valid? on that boolean result, which should likely fail.
You might consider writing your test like so:
describe SomeModel do
let(:image) { FactoryGirl.create(:image) }
context "when changing the parent of the image" do
let(:parent_change) { lambda {
image.captureable = FactoryGirl.create(:parent)
image.save!
} }
it "updates the image's path" do
expect parent_change.to change { image.image.file.path }
end
end
end
This ensures that you only have one assertion in the test (that the file path is changing), and that if the save fails, it will instead raise an exception.
What if I want to do something like
FactoryGirl.define do
factory :leaf do
end
factory :tree do
l = []
leaves do
l << Factory.build(:leaf)
//some app logic here
l
end
root l.first
end
end
How should I write this to make it work?
And maybe somebody have a link with really complex and untrivial examples of using FactoryGirl?
Thank you.
I'm not 100% sure I've followed what you're asking but would this work?
factory :tree do
after_build { |tree|
# build your leaves here
# ...
tree.root l.first
}
end
All I'm trying to do is spec how a one line helper method for a view should behave, but I'm not sure what kind of mock object, (if any) I should be creating if I'm working in Rails.
Here's the code for events_helper.rb:
module EventsHelper
def filter_check_button_path
params[:filter].blank? ? '/images/buttons/bt_search_for_events.gif' : '/images/buttons/bt_refine_this_search.gif'
end
end
And here's my spec code, in events_helper_spec.rb:
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe EventsHelper do
#Delete this example and add some real ones or delete this file
it "should be included in the object returned by #helper" do
included_modules = (class << helper; self; end).send :included_modules
included_modules.should include(EventsHelper)
end
it "should return the 'refine image search' button if a search has been run" do
# mock up params hash
params = {}
params[:filter] = true
# create an instance of the class that should include EventsHelper by default, as the first test has verified (I think)
#event = Event.new
# call method to check output
#event.filter_check_button_path.should be('/images/buttons/bt_search_for_events.gif')
end
end
When I've looked through the docs here - http://rspec.info/rails/writing/views.html, I'm mystified as to where the 'template' object comes from.
I've also tried looking here, which I thought would point me in the right direction, but alas, no dice. http://jakescruggs.blogspot.com/2007/03/mockingstubbing-partials-and-helper.html
What am I doing wrong here?
Thanks,
Chris
You are not doing anything in that spec, just setting a stub, so it will pass, but hasn't tested anything.
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe EventsHelper do
it "should return the 'refine image search' button if a search has been run" do
# mock up params hash
params = {:filter => true}
helper.stub!(:params).and_return(params)
helper.filter_check_button_path.should eql('/images/buttons/bt_search_for_events.gif')
end
end
I'm running my test without spec_helper (Ruby 1.9)
require_relative '../../app/helpers/users_helper'
describe 'UsersHelper' do
include UsersHelper
...
end
Ah,
I asked this question on the rspec mailing list, and one kind soul (thanks Scott!) explained to me that there's a handy helper object for this, that you should use instead, like so:
Rails has its own helper function
params = {:filter => true}
helper.stub!(:params).and_return(params)
I've now updated the code like so:
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe EventsHelper do
#Delete this example and add some real ones or delete this file
it "should be included in the object returned by #helper" do
included_modules = (class << helper; self; end).send :included_modules
included_modules.should include(EventsHelper)
end
it "should return the 'refine image search' button if a search has been run" do
# mock up params hash
params = {}
params[:filter] = true
helper.stub!(:filter_check_button_path).and_return('/images/buttons/bt_search_for_events.gif')
end
end
And it's working. Huzzah!