Reputation: 650
I am having site where users can create products upon signup and products can have checklists.
I am having a checklist table with following columns:-
id | product_id | content | archived
I am new to rails testing. I wrote the test below
test 'should have content' do
checklist = Checklist.new
assert checklist.save
end
and run the test with following command
ruby -I test test/models/checklist_test.rb
and test is failed with Expected false to be truthy error.
Is it because of the problem a checklist can be accessed using user.product.checklists i have to populate the data in fixtures first and call those in testing?
EDIT 1
I don't have any validations in checklist model.
class Checklist < ApplicationRecord
belongs_to :product
end
I added ! in test save like below
test 'should have content' do
checklist = Checklist.new
assert checklist.save!
end
and got this error
ActiveRecord::RecordInvalid: Validation failed: Product must exist
cause the table has product_id in it. I don't know how to supply data to rails test. Any help?
EDIT 2
The error is eliminated after editing like below.
class Checklist < ApplicationRecord
belongs_to :product, optional: true
end
However i want to test the model with product
present. I don't know how to supply data to the test with fixtures as if there is no foreign key i can use Checklist.new
in test.
Since it has foreign key how can i supply data to Checklist
as it belongs to Product
which itself belongs to User
?
Upvotes: 1
Views: 8519
Reputation: 650
I have learned Fixtures to solve this problem.
Fixtures are designed in a way that even associated data(association in model) can be done. For example in my test i have written
checklist = checklists(:one)
to get a test data for checklist. In checklists fixtures(checklists.yml)
one:
product: one
content: Entry
hashtag: '#markets'
archived: false
done: false
where
product: one
refers to :one data in products.yml which is
one:
user: one
name: Test
role: Will decide
and thus association in fixtures is done.
Upvotes: 0
Reputation: 28305
checklist.save
will return false
if the checklist
failed to save for some reason; presumably because a validation failed.
For example, perhaps your app/models/checklists.rb
contains something like:
validates :product_id, presence: true
Or:
validates :content, length: { minimum: 10 }
Etc. In this simple scenario, you can probably easily determine the error by just looking at the model definition; but for a more complex application you could view: checklist.errors.messages
to see a list of reasons why the record failed to save.
Judging by the test name ("should have content"), my guess is that it's failing because content
cannot be blank!
To make this test pass, for example, perhaps you need to write:
test 'should have content' do
checklist = Checklist.new(content: 'hello world')
assert checklist.save
end
One common approach that people use when testing this sort of thing is to define a "valid record" in factories; this lets you explicitly test for invalid records, rather than having to explicitly re-define valid records in lots of place. For example, here you could do:
# test/factories/checklists.rb
FactoryBot.define do
factory :checklist do
content 'test content'
end
end
# test/models/checklist_test.rb
test 'should have content' do
checklist = build(:checklist, content: nil)
refute checklist.save # Expecting this to FAIL!
assert_includes "Content cannot be nil", checklist.errors
end
(Code may not be 100% complete/accurate; but you get the idea)
Upvotes: 5