'Why are tests failing in Ruby on Rails?

I am studying the book "Agile Web Development with Rails 4". In it, at one moment associated with testing, it gives two errors

Error:
ProductsControllerTest#test_should_update_product:
ArgumentError: unknown keywords: :id, :product
    test/controllers/products_controller_test.rb:42:in `block in <class:ProductsControllerTest>'

Error:
ProductsControllerTest#test_should_create_product:
ArgumentError: unknown keyword: :product
    test/controllers/products_controller_test.rb:26:in `block (2 levels) in <class:ProductsControllerTest>'
    test/controllers/products_controller_test.rb:25:in `block in <class:ProductsControllerTest>'

In the same place, the author indicates how to fix them: in the 'setup do' add

@update = {
title: 'Lorem Ipsum',
description: 'Wibbles are fun!',
image_url: 'lorem.jpg',
price: 19.95
}

In 'should_create_product' replace

post products_url, params: { product: { description: @product.description, image_url: @product.image_url, price: @product.price, title: @product.title } }

with

post :create, product: @update

And in 'should_update_product' replace

patch product_url(@product), params: { product: { description: @product.description, image_url: @product.image_url, price: @product.price, title: @product.title } }

with

patch :update, id: @product, product: @update

However, after these fixes, the tests continue to give the same errors. How to fix it?

EDITED: I tried to replace with

post :create, params: { product: @update }

and

patch :update, params: { id: @product, product: @update }

Now it gives to me another errors:

Error:
ProductsControllerTest#test_should_create_product:
URI::InvalidURIError: bad URI(is not URI?): "http://www.example.com:80create"
    test/controllers/products_controller_test.rb:26:in `block (2 levels) in <class:ProductsControllerTest>'
    test/controllers/products_controller_test.rb:25:in `block in <class:ProductsControllerTest>'

Error:
ProductsControllerTest#test_should_update_product:
URI::InvalidURIError: bad URI(is not URI?): "http://www.example.com:80update"
    test/controllers/products_controller_test.rb:42:in `block in <class:ProductsControllerTest>'


Solution 1:[1]

You're mixing up two different kinds of tests.

The first is functional controller tests in the form of ActionController::TestCase which you probably have in your book. These are tests that create a mocked request object and pass it to an instance of the controller. The use of these is greatly discouraged outside of legacy apps since they tend to let tons of bugs through. In functional tests you would write post :create, params: { product: { ... }} because you are actually calling the create method on the controller instance.

The second is integration tests in the form of ActionDispatch::IntegrationTest where you send actual HTTP requests to your Rails application. This is the modern approach and it's just as fast as functional tests in modern versions of Rails which was not the case when the book was written.

In an integration test you pass a path or url:

post '/products', params: { product: ... }

A second issue is the mandatory separation the of keyword parameters that was introduced in Rails 5.

In previous versions of Rails you could call:

get '/foo', bar: 1, baz: 2

And Rails would treat any unknown keys (not params, headers, format, etc) as parameters which was the source of many bugs. In Rails 5+ you explicitly need to pass parameters in the params option.

get '/foo', params: { bar: 1, baz: 2 }

I would suggest you complement the book with some more modern sources or get a newer edition as quite a lot has changed since Rails 4 and following a book that old in Rails 6 is going to be painful.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1