Ruby on Rails Fixtures in sub-directories - ruby-on-rails

I'm using Rails unit testing and fixtures framework. Unless there's a configuration I haven't seen, I can't use the "Advanced Fixtures" (no id objects) from fixtures in sub-directories:
fixtures/people.yml
_fixture:
model_class: Person
myself:
first_name: Me
last_name: Myself
The following call will pass as expected:
fixtures :people
assert(people(:myself)))
while this one will not (after I move people.yml to subdir):
fixtures "subdir/people"
assert(people(:myself)))
In the later case, the error I get is this:
NoMethodError: undefined method `people'
Using Advanced Fixtures seem valuable but having all of my fixture files in the root of /fixtures seems missing something. I have a few test files and I'd like to have various tests use different fixtures directories.
Any input will be appreciated.

I would try saving people.yml in /fixtures/subdir/people.yml. The documentation is here https://apidock.com/rails/ActiveRecord/TestFixtures/ClassMethods/set_fixture_class .
test_helper.rb
set_fixture_class :people => 'Subdir::People'
in your test file.
before do
myself = subdir_people(:myself)
register(myself)
end
it "should test myself" do
assert(people(:myself)))
end

Here is my final solution:
In the fixture file, I kept:
_fixture:
model_class: Person
In the test file, I got:
def people(sym)
subdir_people(sym)
end
def test_myself
assert(people(:myself))
end
That way, it saves me from refactoring my numerous people() calls. Or I can use subdir_people() if I want.

Related

Fixtures in mail preview

Having the following mailer previewer code:
class RegistrationMailerPreview < ActionMailer::Preview
# Preview this email at http://localhost:3000/rails/mailers/registration_mailer/welcome
def welcome
RegistrationMailer.welcome users(:one)
end
end
(full file).
Which is unable to reach my fixtures (users(:one)), return a 500 error status and print out the following error:
NoMethodError: undefined method `users' for #RegistrationMailerPreview
Can we get fixtures entries from mailer previewer?
If yes, I would like to know how to do that.
I have seen that should be possible here, but I can't require test_helper in this file (I don't know why) and I don't understand the difference between ActionMailer::TestCase and ActionMailer::Preview.
If no, is there a way to preview the mail without sending as a parameter User.first, since I could do my tests on a machine on which there is no data filled in the database.
I don't know about the default fixture framework, but I can say using FactoryBot for my fixtures that I was able to use them in my mailer previews simply by prepending the build/create methods with FactoryBot. I didn't need to require anything at the top of the file. i.e.:
class RegistrationMailerPreview < ActionMailer::Preview
def welcome
user = FactoryBot.create(:user)
RegistrationMailer.welcome(user)
end
end
To answer your second question, you could also simply replace the fixture line above with user = User.new(firstname: "Joe"). That would create a new user to use in the preview without persisting it to the database.

Rails 4: Why do fixtures make this test fail?

I have the test below and if there are any fixtures for this model it fails with total_unapproved and new_total being equal instead of new_total being one less.
If I remove loading the fixtures in test_helper.rb or comment them out it runs as I expect.
Here's the class function that sets approvals to true. It definitely works.
def InviteRequest.approve_invites(number)
inv_reqs = InviteRequest.where("approved = ?", false).first(number)
inv_reqs.each do |inv_req|
inv_req.approved = true
inv_req.save
inv_req.send_approved_email
end
end
Here's the test that calls the above function.
require 'test_helper'
class InviteRequestTest < ActiveSupport::TestCase
test "class method approve_invites(number) should approve 'number' InviteRequests" do
# ensure there is at least one instance
inv_req = InviteRequest.create(email: "hobojoe#test.com")
# set all InviteRequests.approved to false
InviteRequest.all.each {|r| r.approved = false; r.save}
total_unapproved = InviteRequest.where("approved = ?", false).count
Rails.logger.info "\nUnapproved Before: #{total_unapproved}"
InviteRequest.approve_invites(1)
new_total = InviteRequest.where("approved = ?", false).count
Rails.logger.info "Unapproved After: #{new_total}\n"
assert_equal total_unapproved - 1, new_total
end
end
Any idea why? I'm not using the fixtures in any other tests but maybe I will someday.
My fixtures weren't valid and changing them fixed the problem.
I'm still not exactly sure how things were failing though.
My fixtures looked like this:
one:
email: MyString
two:
email: MyString
This would fail my uniqueness validation and not save but I'm not sure why the newly created model wouldn't have 'approved' set to true and still be saved since it's correct.
Anyway, changing the fixtures to this fixed things.
one:
email: someguy#example.com
two:
email: somegirl#example.com
Maybe validation fails when you're calling InviteRequest#save? Try to replace save with save! and check to see if the test still passes.
When you use rails generator for new model, fixture file is generated as well looking like this:
one: {}
# column: value
two: {}
# column: value
When you run your tests using fixtures, rails tries to create this 2 empty records. If you have constraint in your migration (such as not null), your tests will fail for obvious reasons.
Solution:
Comment out this empty records in your fixtures files or fill them with something sensible.

Fixtures in RSpec

I'm new to using RSpec for writing tests in a Rails application which uses a MySQL database. I have defined my fixtures and am loading them in my spec as follows:
before(:all) do
fixtures :student
end
Does this declaration save the data defined in my fixtures in the students table or does it just load the data in the table while the tests are running and remove it from the table after all the tests are run?
If you want to use fixtures with RSpec, specify your fixtures in the describe block, not within a before block:
describe StudentsController do
fixtures :students
before do
# more test setup
end
end
Your student fixtures will get loaded into the students table and then rolled back at the end of each test using database transactions.
First of all: You cannot use method fixtures in :all / :context / :suite hook. Do not try to use fixtures in these hooks (like post(:my_post)).
You can prepare fixtures only in describe/context block as Infuse write earlier.
Call
fixtures :students, :teachers
do not load any data into DB! Just prepares helper methods students and teachers.
Demanded records are loaded lazily in the moment when You first try to access them. Right before
dan=students(:dan)
This will load students and teachers in delete all from table + insert fixtures way.
So if you prepare some students in before(:context) hook, they will be gone now!!
Insert of records is done just once in test suite.
Records from fixtures are not deleted at the end of test suite. They are deleted and re-inserted on next test suite run.
example:
#students.yml
dan:
name: Dan
paul:
name: Paul
#teachers.yml
snape:
name: Severus
describe Student do
fixtures :students, :teachers
before(:context) do
#james=Student.create!(name: "James")
end
it "have name" do
expect(Student.find(#james.id)).to be_present
expect(Student.count).to eq 1
expect(Teacher.count).to eq 0
students(:dan)
expect(Student.find_by_name(#james.name)).to be_blank
expect(Student.count).to eq 2
expect(Teacher.count).to eq 1
end
end
#but when fixtures are in DB (after first call), all works as expected (by me)
describe Teacher do
fixtures :teachers # was loaded in previous tests
before(:context) do
#james=Student.create!(name: "James")
#thomas=Teacher.create!(name: "Thomas")
end
it "have name" do
expect(Teacher.find(#thomas.id)).to be_present
expect(Student.count).to eq 3 # :dan, :paul, #james
expect(Teacher.count).to eq 2 # :snape, #thomas
students(:dan)
expect(Teacher.find_by_name(#thomas.name)).to be_present
expect(Student.count).to eq 3
expect(Teacher.count).to eq 2
end
end
All expectations in tests above will pass
If these test are run again (in next suite) and in this order, than expectation
expect(Student.count).to eq 1
will be NOT met! There will be 3 students (:dan, :paul and fresh new #james). All of them will be deleted before students(:dan) and only :paul and :dan will be inserted again.
before(:all) keeps the exact data around, as it's loaded/created once. You do your thing, and at the end of the test it stays. That's why bui's link has after(:all) to destroy or use before(:each); #var.reload!;end to get the latest data from the tests before. I can see using this approach in nested rspec describe blocks.

Making functional tests in Rails with Devise

After 3 years of procrastination today is the day that I start testing my Rails apps. My first step is to fix the failing tests in my Rails 3 beta4 app.
My last 3 failing tests have to do with the devise gem and its authenticate_user! method in a before_filter at the top of my controller.
You'd earn great karma by helping me out with this since it will enable me to use the TDD methodology from now on.
Here is the error that troubles me:
1) Error:
test_should_get_accepted(ModerationControllerTest):
NoMethodError: undefined method `authenticate!' for nil:NilClass
/test/functional/moderation_controller_test.rb:10:in `test_should_get_accepted'
Devise just gives functional tests pointers and helpers in this page: http://github.com/plataformatec/devise but I just don't know how to put this into application.
Can you please give this testing noob some detailed instructions on how to use these helpers?
It took me a while but I found the way. Here it is for anyone stuck at the same point:
At the top of the moderation_controller_test.rb, below the class declaration, add this line:
include Devise::TestHelpers
I have 2 records in my user fixture and I added this line within each test where the user has to be authorized to perform the action.
sign_in User.first
Of course it's dead simple once you know how to do it.
If you want the Devise test helpers to be available to all of your tests, you have to enclose the include mentioned by allesklar at the bottom of test_helper.rb in a class declaration like this:
class ActionController::TestCase
include Devise::TestHelpers
end
Update: 01.25.2017
... rails 5 posts a DEPRECATION WARNING & asks you use ...
Devise::Test::ControllerHelpers
I'm relatively new to Rails, so I'd like to add a couple things that may not be obvious to other new folks.
Concerning the user fixture, I had to define one but leave it empty in order for this to work:
# in users.yml
joe: {}
When using the devise sign_in helper, you can access the hash object directly in your test:
# a test method in some_controller_test.rb
sign_in users(:joe)
See http://guides.rubyonrails.org/testing.html#the-low-down-on-fixtures for more information on Rails fixtures.
Quoting verbatim from https://github.com/plataformatec/devise:
If you're using RSpec, you can put the following inside a file named spec/support/devise.rb:
RSpec.configure do |config|
config.include Devise::TestHelpers, :type => :controller
end
You can now use sign_in and sign_out in your RSpec tests.
In addition to the code in the test_helpers.rb, I added this at the top of the controller_test and it worked for me:
require 'test_helper'

How do you test whether a model has a given method in Rails?

I would like to implement the method User.calculate_hashed_password. I'm trying to use the Shoulda testing library which works with Rails's built-in testing tools, so an answer related to Test::Unit would be just as good as one related to Shoulda (I think).
I'm trying to figure out what I need to test and how I should test it. My initial idea is to do something like...
class UserTest < ActiveSupport::TestCase
should 'Return a hashed password'
assert_not_nil User.calculate_hashed_password
end
end
Is this the right way to do it?
You don't need to test that the method exists, just that the method behaves correctly. Say something like this:
class UserTest < ActiveSupport::TestCase
setup do
#user = User.new
end
should 'Calculate the hashed password correctly'
#user.password = "password"
#user.hashed_password = "xxxxx" # Manually calculate it
end
end
(I don't use shoulda, so excuse any glaring syntax errors.)
That test will fail if the method doesn't exist.
I agree with Otto; but as dylanfm noted, I use #respond_to to test for associations in RSpec.
it "should know about associated Projects" do
#user.should respond_to(:projects)
end
Maybe use respond_to?
You should check out Object#respond_to? and Object#try in newer versions of Rails. If you're new to testing in general, definitely read through this excellent guide on testing in Rails.

Resources