At the end of Chapter 8 of Agile Web Development With Rails, there is a seemingly innocuous exercise that says:

Write some functional tests for the product maintenance application ...

Sounds easy enough :) And I like writing tests. Yes, I'm weird that way.

The existing tests are all happy-path.

require 'test_helper'

class ProductsControllerTest < ActionController::TestCase
setup do
  @product = products(:one)
  @update = {
    title: 'Lorem Ipsum',
    description: 'Wibbles are fun!',
    image_url: 'lorem.jpg',
    price: 19.95
  }
end

test "should create product" do
  assert_difference('Product.count') do
  post :create, product: @update
end

  assert_redirected_to product_path(assigns(:product))
  end
end

And so I decided to try adding a test for when you can't create a product

@invalid_product = {
  price: 0.00,
  title: 'abc'
}

test "should not create product" do
  post :create, product: @invalid_product
  assert_template :new
end

And all was well. Or, almost. There were no tests for the JSON path in the controller:

# POST /products
# POST /products.json
def create
  @product = Product.new(params[:product])

respond_to do |format|
  if @product.save
    format.html { redirect_to @product, notice: 'Product was successfully created.' }
    format.json { render json: @product, status: :created, location: @product }
  else
    format.html { render action: "new" }
    format.json { render json: @product.errors, status: :unprocessable_entity }
  end
end
end

Thinking this would be easy enough to do, I ended up reading an untold number of Stack Overflow posts on the subject; it seems like it's changed between different versions of Rails. Finally, after about an hour, I ended up with something that worked. It seems perfectly simple and obvious in hindsight, but in case anyone else's mind works like mine, here it is :)

test "should not create product (JSON)" do
  post :create, :data =>     @invalid_product.to_json, :format => "json"
  assert_response :unprocessable_entity
end

Note: This is what currently works on Rails 3.2.8 and Ruby 1.9.3p194.