Home > Blockchain >  How can I create new book and assign two authors with it using Rails miniTest?
How can I create new book and assign two authors with it using Rails miniTest?

Time:03-03

Doing TDD

I facing a problem creating a book and assigning two authors with it. There is a failure in the creation. It says that there is an AssociationTypeMismatch: Author(#15100) expected, got nil which is an instance of NilClass(#40. I suppose that the format "authors: []" is not have been read well by something.

This is the test:

def test_has_many_and_belongs_to_mapping
 apress = Publisher.find_by(name: 'Apress')
 assert_equal 2, apress.books.size

 book = Book.new(
  title: 'Rails E-Commerce 3nd Edition',
  authors: [
    Author.find_by(first_name: 'Christian', last_name: 'Hellsten'),
    Author.find_by(first_name: 'Jarkko', last_name: 'Laine')
  ],
  published_at: Time.now,
  isbn: '123-123-123-x',
  blurb: 'E-Commerce on Rails',
  page_count: 300,
  price: 30.5
 )

 # apress.books << book

 # apress.reload
 # book.reload

 # assert_equal 3, apress.books.size
 # assert_equal 'Apress', book.publisher.name
end

This is the error:

enter image description here

MY ERD:

enter image description here

My schema:

enter image description here

CodePudding user response:

I think what you are missing is a meaningful setup of data needed before this test runs. Even though those publishers and books may exist in your development environment/database, the test suite usually is configured to wipe the database clean between runs.

If you have fixtures defined, then you can reference them like this:

test/fixtures/publishers.yml

apress:
  id: 1
  name: Apress

test/fixtures/authors.yml

hellsten:
  id: 1
  first_name: Christian
  last_name: Hellsten

laine:
  id: 2
  first_name: Jarkko
  last_name: Laine

test/fixtures/books.yml

beginning_ruby:
  title: Beginning Ruby
  publisher_id: 1

ruby_recipes:
  title: Ruby Recipes
  publisher_id: 1

So that the test would look more like this:

def test_has_many_and_belongs_to_mapping
 apress = publishers(:apress)
 assert_equal 2, apress.books.size

 book = Book.new(
  title: 'Rails E-Commerce 3nd Edition',
  authors: [
    Author.find_by(first_name: 'Christian', last_name: 'Hellsten'),
    Author.find_by(first_name: 'Jarkko', last_name: 'Laine')
  ],
  published_at: Time.now,
  isbn: '123-123-123-x',
  blurb: 'E-Commerce on Rails',
  page_count: 300,
  price: 30.5
 )

 apress.books << book

 apress.reload
 book.reload

 assert_equal 3, apress.books.size
 assert_equal 'Apress', book.publisher.name
end

Or instead of using fixtures, you could create the content before the test:

So that the test would look more like this:

setup do
  publisher = Publisher.create!(name: 'Apress')
  publisher.books.create!(title: 'Beginning Ruby')
  publisher.books.create!(title: 'Ruby Recipes')
  Author.create!(first_name: 'Christian', last_name: 'Hellsten')
  Author.create!(first_name: 'Jarkko', last_name: 'Laine')
end

def test_has_many_and_belongs_to_mapping
 apress = Publisher.find_by(name: 'Apress')
 assert_equal 2, apress.books.size

 book = Book.new(
  title: 'Rails E-Commerce 3nd Edition',
  authors: [
    Author.find_by(first_name: 'Christian', last_name: 'Hellsten'),
    Author.find_by(first_name: 'Jarkko', last_name: 'Laine')
  ],
  published_at: Time.now,
  isbn: '123-123-123-x',
  blurb: 'E-Commerce on Rails',
  page_count: 300,
  price: 30.5
 )

 apress.books << book

 apress.reload
 book.reload

 assert_equal 3, apress.books.size
 assert_equal 'Apress', book.publisher.name
end

That way your database has those values, and your find_by() calls should return data, and not nil.

  • Related