Praveen KJ
Praveen KJ

Reputation: 650

Rails testing a model says 'Expected false to be truthy'

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

Answers (2)

Praveen KJ
Praveen KJ

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

Tom Lord
Tom Lord

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

Related Questions