Getting Started with – Automated Testing – Stubs are like viruses



Getting Started with – Automated Testing – Stubs are like viruses

0 0


dcrug-talk

Intro to Testing talk @ DCRUG

On Github AlwaysBCoding / dcrug-talk

Getting Started with

Automated Testing

Jordan Leigh

@AlwaysBCoding

The Rails Testing Ecosystem

  • Unit Tests
  • Integration Tests
  • RSpec
  • Test Unit
  • MiniTest
  • Capybara
  • Cucumber
  • Webrat
  • Selenium
  • Jasmine
  • Stubs
  • Mocks
  • VCR
  • Surrogate

The Six Steps

? ? ? ? ? ?

What is Automated Testing?

app/models/user.rb

class User
  attr_accessible :email

  validates :email, with: ?
end

app/models/user.rb

class User
  attr_accessible :email

  validates :email, with: /[A-Z0-9._%-]+@[A-Z0-9.-]+\.[A-Z]{2,4}/
end

app/models/user.rb

class User
  attr_accessible :email

  validates :email, with: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,6}$/
end

Automated Testing != Test Driven Development

Unit vs. Integration

Popular Unit Testing Gems

The Six Steps

Use RSpec to write Unit Tests ? ? ? ? ?

So... how do we write a test?

spec/models/user_spec.rb

describe User do

  context "User Creation" do

    it "allows an email address with a + in the first section" do
    end

  end

end

spec/models/user_spec.rb

describe User do

  context "User Creation" do

    it "allows an email address with a + in the first section" do
      # ARRANGE
      # ACT
      # ASSERT
    end

  end

end

spec/models/user_spec.rb

describe User do

  context "User Creation" do

    it "allows an email address with a + in the first section" do
      test_user = User.new(email: "something+something@gmail.com")
      # ACT
      # ASSERT
    end

  end

end

spec/models/user_spec.rb

describe User do

  context "User Creation" do

    it "allows an email address with a + in the first section" do
      test_user = User.new(email: "something+something@gmail.com")
      test_user.save!
      # ASSERT
    end

  end

end

spec/models/user_spec.rb

describe User do

  context "User Creation" do

    it "allows an email address with a + in the first section" do
      test_user = User.new(email: "something+something@gmail.com")
      test_user.save!
      test_user.should have(0).errors_on(:email)
    end

  end

end

spec/models/user_spec.rb

describe User do

  context "User Creation" do

    it "allows an email address with a + in the first section" do
      test_user = User.new(email: "something+something@gmail.com")
      test_user.save!
      test_user.should have(0).errors_on(:email)
    end

    it "does not allow an email address without an @ in between sections" do
      # ARRANGE
      # ACT
      # ASSERT
    end

  end

end

spec/models/user_spec.rb

describe User do

  context "User Creation" do

    it "allows an email address with a + in the first section" do
      test_user = User.new(email: "something+something@gmail.com")
      test_user.save!
      test_user.should have(0).errors_on(:email)
    end

    it "does not allow an email address without an @ in between sections" do
      test_user = User.new(email: "namegmail.com")
      # ACT
      # ASSERT
    end

  end

end

spec/models/user_spec.rb

describe User do

  context "User Creation" do

    it "allows an email address with a + in the first section" do
      test_user = User.new(email: "something+something@gmail.com")
      test_user.save!
      test_user.should have(0).errors_on(:email)
    end

    it "does not allow an email address without an @ in between sections" do
      test_user = User.new(email: "namegmail.com")
      test_user.save!
      # ASSERT
    end

  end

end

spec/models/user_spec.rb

describe User do

  context "User Creation" do

    it "allows an email address with a + in the first section" do
      test_user = User.new(email: "something+something@gmail.com")
      test_user.save!
      test_user.should have(0).errors_on(:email)
    end

    it "does not allow an email address without an @ in between sections" do
      test_user = User.new(email: "namegmail.com")
      test_user.save!
      test_user.should have(1).error_on(:email)
    end

  end

end

The Six Steps

Use RSpec to write Unit Tests Arrange. Act. Assert. ? ? ? ?

app/models/user.rb

class User < ActiveRecord::Base

  attr_accessible :email, :firstname, :lastname

  validates :email, with: /[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,10}/

  def display_name
    "#{firstname} #{lastname}"
  end

end

spec/models/user_spec.rb

describe User do

  context "decorators" do

    describe "#display_name" do

      it "displays the firstname and lastname separated by a space" do
        # ARRANGE
        # ACT
        # ASSERT
      end

    end

  end

end

spec/models/user_spec.rb

describe User do

  context "decorators" do

    describe "#display_name" do

      it "displays the firstname and lastname separated by a space" do
        test_user = User.create!(firstname: "John", lastname: "Wall")
        # ACT
        # ASSERT
      end

    end

  end

end

spec/models/user_spec.rb

describe User do

  context "decorators" do

    describe "#display_name" do

      it "displays the firstname and lastname separated by a space" do
        test_user = User.create!(firstname: "John", lastname: "Wall")
        name_displayed = test_user.display_name
        # ASSERT
      end

    end

  end

end

spec/models/user_spec.rb

describe User do

  context "decorators" do

    describe "#display_name" do

      it "displays the firstname and lastname separated by a space" do
        test_user = User.create!(firstname: "John", lastname: "Wall")
        name_displayed = test_user.display_name
        name_displayed.should eq "John Wall"
      end

    end

  end

end

The Six Steps

Use RSpec to write Unit Tests Arrange. Act. Assert. Abstract model creation into factories ? ? ?

Popular Factory Gems

spec/factories/user_factory.rb

FactoryGirl.define do

  factory :user do

    email "JohnWall@gmail.com"
    firstname "John"
    lastname "Wall"

  end

end

spec/models/user_spec.rb

describe User do

  context "decorators" do

    describe "#display_name" do

      it "displays the firstname and lastname of a user separated by a space" do
        test_user = FactoryGirl.create(:user)
        display_name = test_user.display_name
        display_name.should eq "John Wall"
      end

    end

  end

end

Testing API's is hard

app/models/user.rb

class User < ActiveRecord::Base

  attr_accessible :email, :firstname, :lastname, :stripe_customer_id

  validates :email, with: /[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,10}/

  def display_name
    "#{firstname} #{lastname}"
  end

  def create_stripe_customer(card_token)
    stripe_api_response = create_stripe_customer_api_call(card_token)
    self.stripe_customer_id = stripe_api_response.id
    self.save!
  end

  def create_stripe_customer_api_call(card_token)
    Stripe::Customer.create(card: card_token, description: self.email)
  end

end

spec/models/user_spec.rb

describe User do

  context "payments" do

    describe "#create_stripe_customer" do

      it "displays the firstname and lastname of a user separated by a space" do
        test_user = FactoryGirl.create(:user)
        test_user.create_stripe_customer(card_token???)
        test_user.stripe_customer_id = ???
      end

    end

  end

end

Let's talk about viruses

Stubs are like viruses

app/models/user.rb

class User < ActiveRecord::Base

  attr_accessible :email, :firstname, :lastname, :stripe_customer_id

  validates :email, with: /[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,10}/

  def display_name
    "#{firstname} #{lastname}"
  end

  def create_stripe_customer(card_token)
    stripe_api_response = create_stripe_customer_api_call(card_token)
    self.stripe_customer_id = stripe_api_response.id
    self.save!
  end

  def create_stripe_customer_api_call(card_token)
    Stripe::Customer.create(card: card_token, description: self.email)
  end

end

spec/factories/user_factory.rb

FactoryGirl.define do

	factory :user do

		email "JohnWall@gmail.com"
		firstname "John"
		lastname "Wall"

		after(:build) do |user|
		  user.stub(:create_stripe_customer_api_call).and_return(OpenStruct.new(id: "customer_1234"))
		end

	end

end

spec/models/user_spec.rb

describe User do

  context "payments" do

    describe "#create_stripe_customer" do

      it "displays the firstname and lastname of a user separated by a space" do
        test_user = FactoryGirl.create(:user)
        test_user.create_stripe_customer("xyz")
        test_user.stripe_customer_id = "customer_1234"
      end

    end

  end

end

Don't lose track of reality

The Six Steps

Use RSpec to write Unit Tests Arrange. Act. Assert. Abstract model creation into factories Stub out API Calls ? ?

So... what do we test?

Vending Machines!

Arrange

Act

Assert

Interface vs. Implementation

Fragile tests are bad

The Six Steps

Use RSpec to write Unit Tests Arrange. Act. Assert. Abstract model creation into factories Stub out API Calls Test the interface NOT the implementation Have Fun?

Jordan Leigh

@AlwaysBCoding