Giter Site home page Giter Site logo

rspec_controller_testing's Introduction

#Yogurt Controller Specs

###Objectives

  • Understand how to create RSpec Controller Tests
  • Initialize RSpec for controller
  • Utilize RSpec Methods

Methods to learn

render_template(:view_filename)
be_success
include([array, of, things])
eq()
be_a(Class)
be_persisted
redirect_to(path or path_helper)
change(Class, :count).by(num)

###Setup

Initialize our Yogurt app

$ rails new yogurt_app -T

Put in the rspec-rails gem

gem 'rspec-rails'

Bundle

bundle install

Initialize rspec

$ rails g rspec:install

Create a controller

$ rails g controller yogurts

Create a model

$ rails g model yogurt name calories:integer

For now, let's delete the spec/helpers for now

###Writing our first controller test for index

Let's write a test to check the http status when we go to a page

require 'rails_helper'

RSpec.describe YogurtsController, type: :controller do

  describe "GET #index" do
    it "returns http success" do
      get :index
      expect(response).to have_http_status(:success)
    end
  end
  
  it "renders the index template" do
      get :index
      expect(response).to render_template("index")
    end

end	

Let's go to routes.rb and add resources :yogurts

Then, add in the views/yogurts/ and add index.html.erb

Finally, add the method into our yogurts_controller.rb

def index
	@yogurts = Yogurt.all
end

In your terminal, run

$ rspec spec/controllers/yogurts_controller_spec.rb

Your test should pass now

##NOW...

It sucks to write get :index every time. So lets do this:

before(:each){
  get :index
}

Now our code looks cleaner

  describe "GET index" do

    # add get :index before all tests here
    before(:each){
      get :index
    }

    it "returns http success" do
      expect(response).to have_http_status(:success)
    end

    it "renders the index template" do
      expect(response).to render_template("index")
    end
  end

###Before we finish index...

Let's test and see if our action works. Add these lines to the index tests

let!(:yogurt1){Yogurt.create!(name: "Stanley's Chocolate Cake", calories: 350)}
let!(:yogurt2){Yogurt.create!(name: "Rob's Glassy Mix", calories: 380)}

...

it "assigns all the yogurts to yogurts" do
  expect(assigns(:yogurts)).to include(yogurt1, yogurt2)
end

Now we thoroughly tested your controller action!

###Activity

Write the http status check for the new action 

###Writing new together

Let's write a test to check the http status of new

  describe "GET new" do

    before(:each){
      get :new
    }

    it "returns http success" do
      expect(response).to have_http_status(:success)
    end

    it "renders the index template" do
      expect(response).to render_template("new")
    end
  end

Then, add in the views/yogurts/ and add new.html.erb

Finally, add the method into our yogurts_controller.rb

def new
	@yogurt = Yogurt.new
end

Then, we want to check if there is a Yogurt instance variable with Yogurt.new

it "assigns a new yogurt to a variable yogurt" do
  expect(assigns(:yogurt)).to be_a(Yogurt)
end

To check if the new page doesn't create any new records, run this test

it "doesn't save any new records" do
  expect{get :new}.to change(Yogurt, :count).by(0)
end

In your terminal, run

$ rspec spec/controllers/yogurts_controller_spec.rb

Your tests should all pass now!

###Creating show page tests

describe "GET show" do
    let!(:yogurt){Yogurt.create!(name: "Jackie Cake", calories: 450)}

    before(:each){
      get :show, id: yogurt.id
    }

    it "is successful" do
      expect(response).to be_success
    end

    it "renders the show view file" do
      expect(response).to render_template(:show)
    end

    it "assigns the requested yogurt to a variable yogurt" do
      expect(assigns(:yogurt)).to eq(yogurt)
    end
  end

Now, pass them by creating a show.html.erb in views/yogurts. Then in yogurts_controller.rb add

def show
    @yogurt = Yogurt.find(params[:id])
end

In your terminal, run

$ rspec spec/controllers/yogurts_controller_spec.rb

Your tests should all pass now!

###Activity

Now knowing what we know with `show`, spend 5 minutes and try and create tests and pass edit!

##Writing edit together

describe "GET edit" do
    let!(:yogurt){Yogurt.create!(name: "Bang bang", calories: 450)}

    before(:each){
      get :edit, id: yogurt.id
    }

    it 'is successful' do
      expect(response).to be_success
    end

    it "renders the edit view file" do
      expect(response).to render_template(:edit)
    end

    it 'assigns the requested yogurt to a variable yogurt' do
      expect(assigns(:yogurt)).to eq(yogurt)
    end
  end

To pass it, create edit.html.erb inside the views/yogurts folder and add in the yogurts_controller.rb

 def edit
    @yogurt = Yogurt.find(params[:id])
  end

In your terminal, run

$ rspec spec/controllers/yogurts_controller_spec.rb

Your tests should all pass now!

###Testing POST action

Add these tests

describe "POST create" do
    context "when form is valid" do
      let!(:valid_attributes) do
        {name: "Honey Boo Boo", calories: 20000}
      end

      it "added a yogurt record" do
        expect{post :create, yogurt: valid_attributes}.to change(Yogurt, :count).by(1)
      end

      it "redirects to the index" do
        post :create, yogurt: valid_attributes
        expect(response).to redirect_to yogurts_path
      end
    end

    context "when form is invalid" do
      let!(:bad_attributes) do
        {name: nil, calories: nil}
      end

      it "does not add a yogurt record" do
        expect{post :create, yogurt: bad_attributes}.to change(Yogurt, :count).by(0)
      end

      it "renders the new view file" do
	      post :create, yogurt: bad_attributes
        expect(response).to render_template(:new)
      end
    end
  end

###Now, try and pass it

Create your create action

def create
    @yogurt = Yogurt.new(yogurt_params)

    if @yogurt.save
      redirect_to yogurts_path
    else
      render :new
    end
  end

private

def yogurt_params
  params.require(:yogurt).permit(:name, :calories)
end	  

You now have to validate your model

class Yogurt < ActiveRecord::Base
  validates_presence_of :name, :calories
  validates_numericality_of :calories
end

In your terminal, run

$ rspec spec/controllers/yogurts_controller_spec.rb

Your tests should all pass now!

##Update tests

describe 'PUT update' do
    let!(:yogurt){Yogurt.create!(name: "Sweet Bear", calories: 350)}

    context "update with valid attributes" do
      let!(:valid_attributes) do
        {
          name: "Mandy Moore",
          calories: 450
        }
      end

      it "updates the existing yogurt" do
        put :update, id: yogurt.id, yogurt: valid_attributes
        expect(yogurt.reload.name).to eq(valid_attributes[:name])
      end

      it "redirects to the index" do
        put :update, id: yogurt.id, yogurt: valid_attributes
        expect(response).to redirect_to yogurts_path
      end

    end

    context "update with bad attributes" do
      let(:invalid_attributes) do
        {
          name:nil,
          calories:nil
        }
      end

      it "does not update the existing yogurt" do
        put :update, id: yogurt.id, yogurt: invalid_attributes
        expect(yogurt.reload.name).to eq(yogurt.name)
      end

      it "renders the edit view file" do
        put :update, id: yogurt.id, yogurt: invalid_attributes
        expect(response).to render_template :edit
      end

    end

  end

Pass the tests!

def update
    @yogurt = Yogurt.find(params[:id])

    if @yogurt.update(yogurt_params)
      redirect_to yogurts_path
    else
      render :edit
    end
  end

In your terminal, run

$ rspec spec/controllers/yogurts_controller_spec.rb

Your tests should all pass now!

##Destroy Tests

Let's write tests for destroy

describe 'DELETE destroy' do
    let!(:yogurt){Yogurt.create!(name: 'Happy feet', calories: 500)}

    it "should assign the yogurt to a variable yogurt" do
      delete :destroy, id: yogurt.id
      expect(assigns(:yogurt)).to eq(yogurt)
    end

    it "should destroy a yogurt record" do
      expect{delete :destroy, id: yogurt.id}.to change(Yogurt, :count).by(-1)
    end
  end

Then, pass the tests

def destroy
    @yogurt = Yogurt.find(params[:id])
    @yogurt.destroy
    redirect_to yogurts_path
  end	

In your terminal, run

$ rspec spec/controllers/yogurts_controller_spec.rb

Your tests should all pass now!

rspec_controller_testing's People

Contributors

stanleycyang avatar

Stargazers

Dmitriy Shramko avatar Ladan Nasserian avatar

Watchers

James Cloos avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.