Controller Testing: You're Doing It Wrong
-
Upload
johnnygroundwork -
Category
Engineering
-
view
114 -
download
0
description
Transcript of Controller Testing: You're Doing It Wrong
![Page 1: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/1.jpg)
Controller Testing
“You’re doing it wrong”
Jonathan Mukai-Heidt
![Page 2: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/2.jpg)
Hello!
![Page 3: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/3.jpg)
Groundwork
![Page 4: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/4.jpg)
Let’s talk controller tests
![Page 5: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/5.jpg)
Almost no one knows how to test controllers
![Page 6: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/6.jpg)
Many, many, many different projects
Two years consulting at Pivotal Labs
Kicked around NYC start up scene
Freelance software developer
![Page 7: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/7.jpg)
Controller Testing Hall of Shame
![Page 8: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/8.jpg)
Wait, testing… why?
![Page 9: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/9.jpg)
Catching regressions
![Page 10: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/10.jpg)
Developing code in isolation!!!
![Page 11: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/11.jpg)
Driving modular, composable code!!!
![Page 12: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/12.jpg)
Back to the Hall of Shame
![Page 13: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/13.jpg)
Stub all the things
describe "#show" do subject { -> { get :show, id: id } } let(:id) { '77' } let(:pizza) { Pizza.new }
context "with an existing pizza" do before { Pizza.should_receive(:find).with(id).and_return(pizza) } it { assigns(:pizza).should == pizza } end
context "with a non-existent pizza" do before { Pizza.should_receive(:find).with(id).and_raise_error(ActiveRecord::RecordNotFound) it { should raise_error(ActiveRecord::RecordNotFound) } endend
![Page 14: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/14.jpg)
Everything is integration
As a userGiven there is a pepperoni pizzaWhen I visit the pizza index pageAnd I click on "pepperoni"Then I should see the pepperoni pizza
![Page 15: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/15.jpg)
render_views
![Page 16: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/16.jpg)
No tests at all…
![Page 17: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/17.jpg)
Often the things that really matter are untested
![Page 18: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/18.jpg)
Controllers often have a “big action” and “small details”
![Page 19: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/19.jpg)
“Big” concerns should be the same!
Fetch or create/update a resource
![Page 20: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/20.jpg)
“Small” concerns are actually very important
Require authentication?
Who is authorized?
What formats?
![Page 21: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/21.jpg)
I was also confused
![Page 22: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/22.jpg)
One day…
![Page 23: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/23.jpg)
Rails controllers (+ responders) are awesomely declarative
![Page 24: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/24.jpg)
What do we really mean when we say declarative
![Page 25: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/25.jpg)
Imperative / Declarative
![Page 26: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/26.jpg)
Describe the properties we want
![Page 27: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/27.jpg)
No logic (really!)
![Page 28: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/28.jpg)
Imperative“When deleting a user, if the current user is an admin user, then allow the deletion; if the current user is not an admin, do not allow the deletion to finish.”
![Page 29: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/29.jpg)
Declarative“Only admin users can delete another user.”
![Page 30: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/30.jpg)
Imperative“When a request for a resource comes in, if the request is for JSON, then fetch the resource and render it from the JSON template; if the request is for HTML, then fetch the resource and render the HTML template; if the request is for another format like PDF, return an error.”
![Page 31: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/31.jpg)
Declarative“This controller returns a resource represented as JSON or HTML.”
![Page 32: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/32.jpg)
Ruby is imperative but it lets us write declarative code
![Page 33: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/33.jpg)
Look at how declarative Rails controllers can be
![Page 34: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/34.jpg)
before_filter
# let's us do things like
before_filter :authenticate_user!, except: :show
![Page 35: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/35.jpg)
before_filter
# ...or...
before_filter :load_some_model, except: [:new, :index]
![Page 36: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/36.jpg)
Authorization
# Using Authority gem
authorize_actions_for SomeResource
![Page 37: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/37.jpg)
Authorization
# Using CanCan gem
load_and_authorize_resource :some_resource
![Page 38: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/38.jpg)
Rails 4 + Responders
![Page 39: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/39.jpg)
respond_to
# quickly declare formats
respond_to :html, :json
![Page 40: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/40.jpg)
SHOW
def new respond_with(@pizza)end
![Page 41: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/41.jpg)
CREATE
def create respond_with(@pizza = Pizza.create(pizza_params))end
![Page 42: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/42.jpg)
…and so on…
![Page 43: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/43.jpg)
Little to no logic in controllers
![Page 44: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/44.jpg)
And this is great!
![Page 45: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/45.jpg)
But it’s not what 90% of the controllers I come across look like
![Page 46: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/46.jpg)
Because of muddying these nice declarative controllers with business logic
![Page 47: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/47.jpg)
Business logic belongs in modelsYou’ve heard this many times already
![Page 48: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/48.jpg)
What do we really care about in controllers?
![Page 49: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/49.jpg)
Authentication
![Page 50: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/50.jpg)
Authorization
![Page 51: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/51.jpg)
Presence of resourceWhat resource are we working with
![Page 52: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/52.jpg)
Response
![Page 53: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/53.jpg)
Tests should help us write better code
![Page 54: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/54.jpg)
Declarative controller? Declarative tests!
![Page 55: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/55.jpg)
What does it look like in action?
![Page 56: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/56.jpg)
Shared examples cover the “small” details
![Page 57: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/57.jpg)
“Big” actions can be simple…
# e.g. a show actionit { should assign(:some_resource) }
# e.g. a create actionit { should change(Pizza, :count).by(+1) }
![Page 58: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/58.jpg)
Authentication
describe CommentsController do let(:current_user) { users(:claude) } let(:blog_post) { blog_posts(:top_ten_pizzas) }
describe "#new" do subject { -> { get :new, blog_post_id: blog_post } }
context "with a logged in user" do before { sign_in(:user, current_user) }
it "should not redirect to the login page" do response.should_not be_redirect end end
context "with an unauthenticated user" do it "should redirect to the login page" do response.should be_redirect_to(sign_in_path) end end endend
![Page 59: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/59.jpg)
Authentication shared example
shared_examples_for "an action that requires a login" do before { sign_out :user } it { should respond_with_redirect_to(sign_in_path) }end
![Page 60: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/60.jpg)
Authentication shared example in action
describe CommentsController do let(:current_user) { users(:claude) } let(:blog_post) { blog_posts(:top_ten_pizzas) }
before { sign_in(:user, current_user) }
describe "#new" do subject { -> { get :new, blog_post_id: blog_post } }
it_should_behave_like "an action that requires a login" endend
![Page 61: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/61.jpg)
Authorization
describe "#create" do subject { -> { post :create, blog_post_id: blog_post, comment: params } }
let(:params) { { body: "What a great post. I loved the part about shared examples." } }
before { sign_in :user, current_user }
context "with an authorized user" do let(:current_user) { users(:bob) }
it "should respond with created" do response.should respond_with 201 end end
context "with an unauthorized user" do let(:current_user) { users(:mallory) }
it "should respond with 404" do response.should respond_with 404 end endend
![Page 62: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/62.jpg)
“Malicious Mallory”
![Page 63: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/63.jpg)
Authorization shared example
shared_examples_for "an action that requires authorization" do before { sign_in :user, users(:mallory) } it { should respond_with 404 }end
![Page 64: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/64.jpg)
Authorization shared example in action
describe "#create" do subject { -> { post :create, blog_post_id: blog_post, comment: params } }
let(:params) { { body: "What a great post. I loved the part about shared examples." } }
before { sign_in :user, users(:bob) }
it_should_behave_like "a non-navigation action that requires a login" it_should_behave_like "an action that requires authorization"end
![Page 65: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/65.jpg)
Presence of Resource
![Page 66: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/66.jpg)
Presence shared example
shared_examples_for "an action that requires" do |*resources| resources.each do |resource| context "with an invalid or missing #{resource}" do let(resource) { double(to_param: "does-not-exist", reload: nil) } it { should respond_with 404 } end endend
![Page 67: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/67.jpg)
Presence shared example in action
describe PizzaController do describe "#show" do subject { -> { get :show, id: pizza, format: format } } let(:pizza) { pizzas(:pepperoni) }
it_should_behave_like "an action that requires", :pizza endend
![Page 68: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/68.jpg)
Response
![Page 69: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/69.jpg)
Response shared example
shared_examples_for "an action that returns" do |*acceptable_formats| acceptable_formats.each do |acceptable_format| context "expecting a response in #{acceptable_format} format" do let(:format) { acceptable_format } it { should_not respond_with_status(:not_acceptable) } end end
(%i(html js json xml csv) - acceptable_formats.collect(&:to_sym)).each do |unacceptable_format| context "expecting a response in #{unacceptable_format} format" do let(:format) { unacceptable_format } it { should respond_with_status(:not_acceptable) } end endend
![Page 70: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/70.jpg)
Response shared example in action
describe CommentsController do let(:current_user) { users(:claude) } let(:blog_post) { blog_posts(:top_ten_pizzas) } let(:format) { :html }
before { sign_in :user, current_user }
describe "#show" do subject { -> { get :show, id: comment, format: format } } let(:comment) { blog_post.comments.first }
it_should_behave_like "an action that returns", :html end
describe "#create" do subject { -> { post :create, blog_post_id: blog_post, comment: params, format: format } } let(:params) { { body: "What a great post. I loved the part about shared examples." } }
it_should_behave_like "an action that returns", :html, :json endend
![Page 71: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/71.jpg)
Your test is like a check list
![Page 72: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/72.jpg)
But what about…Likes/Bookmarks/Ratings
Bulk creates
Merging records
Actions that touch several models
![Page 73: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/73.jpg)
“Skinny controller, fat model”
Ever since I began Rails work people have been saying this
![Page 74: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/74.jpg)
5/6 projects suffer from bloated controllers
![Page 75: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/75.jpg)
ActiveModel
![Page 76: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/76.jpg)
Use it!
![Page 77: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/77.jpg)
There is no resource too small
![Page 78: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/78.jpg)
Models are cheap, especially ones not tied to the DB
![Page 79: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/79.jpg)
An illustrative example
![Page 80: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/80.jpg)
Password ResetClient wanted to overhaul a legacy password reset workflow
![Page 81: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/81.jpg)
Suspend your dis-belief, they are not using Devise yet
![Page 82: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/82.jpg)
Too simple to break out into a model?
![Page 83: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/83.jpg)
Requirements always change“Ah but wait, we want to tell users if they put in their e-mail wrong.”
![Page 84: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/84.jpg)
Of course requirements change again“If the user is locked out of their account, we shouldn’t send a password reset.”
![Page 85: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/85.jpg)
Suddenly, a fat controller
![Page 86: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/86.jpg)
ActiveModel makes it simple
![Page 87: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/87.jpg)
Think nouns (resources), not verbs
![Page 88: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/88.jpg)
HTTP gives you all the verbs you need
![Page 89: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/89.jpg)
FootworkNo gem!
This will vary from project to project
Figure out how your project will handle these situations
![Page 90: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/90.jpg)
Habbits
![Page 91: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/91.jpg)
Hence the controller checklist
![Page 92: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/92.jpg)
The rewards are great!
![Page 93: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/93.jpg)
Easier to test
![Page 94: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/94.jpg)
Drives good design
![Page 95: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/95.jpg)
Keep controllers simple
![Page 96: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/96.jpg)
Logic goes in models where it belongs
![Page 97: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/97.jpg)
No confusion about where things go (bulk creates, likes, etc)
![Page 98: Controller Testing: You're Doing It Wrong](https://reader034.fdocuments.us/reader034/viewer/2022051013/547e51dcb4af9f9b158b569f/html5/thumbnails/98.jpg)
Uniform controllers == less dev time