SlideShare uma empresa Scribd logo
1 de 53
You’re Doing It Wrong

           Chad Pytel
     cpytel@thoughtbot.com
            @cpytel
You’re Doing It Wrong
      but I love you anyway




           Chad Pytel
     cpytel@thoughtbot.com
            @cpytel
Rake Tasks
Are you testing them?
What makes them hard to test?

   • Scripts that live outside app
   • Often have network and file access
   • Often have output
Example Task

namespace :twitter do
  task :search => :environment do
    puts "Searching twitter."
    Twitter.search("@cpytel").each do |result|
      puts "Processing #{result.inspect}."
      alert = Alert.create(:body => result)
      alert.save_cache_file!
    end
  end
  puts "All done!"
end
One possible way to test
context "rake twitter:search" do
  setup do
    # How slow is this going to be? Very.
    @out = `cd #{Rails.root} &&
           rake twitter:search 2>&1`
  end
should "print a message at the beginning" do
  assert_match /Searching/i, @out
end
should "find all tweets containing @cpytel" do
  # this one would be based entirely on luck.
end
This Has Problems

• Slow
• No mocking or stubbing available
• Task isn’t in a transaction
Basically, no sandboxing
How do we fix this?
Rake tasks are just Ruby
Move it all into the Model
class Alert < ActiveRecord::Base
  def self.create_all_from_twitter_search(output = $stdout)
    output.puts "Searching twitter."
    Twitter.search("@cpytel").each do |result|
      output.puts "Processing #{result.inspect}."
      alert = create(:body => result)
      alert.save_cache_file!
    end
    output.puts "All done!"
  end

  def save_cache_file!
    # Removes a file from the filesystem.
  end
end
The Task is Nice and Skinny

namespace :twitter do
  task :search => :environment do
    Alert.create_all_from_twitter_search
  end
end
Testing is Pretty Normal

# test/unit/alert_test.rb
class AlertTest < ActiveSupport::TestCase
  context "create_all_from_twitter_search" do
    setup do
      # Make sure none of the tests below hit the
      # network or touch the filesystem.
      Alert.any_instance.stubs(:save_cache_file!)
      Twitter.stubs(:search).returns([])
      @output = StringIO.new
    end
should "print a message at the beginning" do
  Alert.create_all_from_twitter_search(@output)
  assert_match /Searching/i, @output.string
end
should "save some cache files" do
  Twitter.stubs(:search).returns(["one"])
  alert = mock("alert")
  alert.expects(:save_cache_file!)
  Alert.stubs(:create).returns(alert)
  Alert.create_all_from_twitter_search(@output)
end
should "find all tweets containing @cpytel" do
  Twitter.expects(:search).
          with("@cpytel").
          returns(["body"])
  Alert.create_all_from_twitter_search(@output)
end
We can mock and stub!
We can use normal tools!


• FakeWeb/WebMock
• FileUtils::NoWrite
In Summary

• You can test drive development of
  your rake tasks
• Rake tasks should live inside a
  model (or class)
Views
Know Your Helpers
Know How They Change
# Edit form
<%= form_for :user,
             :url => user_path(@user),
             :html => {:method => :put} do |form| %>
<%= form_for @user do |form| %>
<!-- posts/index.html.erb -->
<% @posts.each do |post| -%>
  <h2><%= post.title %></h2>
  <%= format_content post.body %>
  <p>
    <%= link_to 'Email author',
                mail_to(post.user.email) %>
  </p>
<% end -%>
Move the post content
    into a partial
<!-- posts/index.html.erb -->
<% @posts.each do |post| -%>
  <%= render :partial => 'post', :object => :post %>
<% end -%>

<!-- posts/_post.erb -->
<h2><%= post.title %></h2>
<%= format_content post.body %>
<p><%= link_to 'Email author',
mail_to(post.user.email) %></p>
Looping was built
  into render
<!-- posts/index.html.erb -->
<%= render :partial => 'post', :collection => @posts %>

<!-- posts/_post.erb -->
<h2><%= post.title %></h2>
<%= format_content post.body %>
<p>
  <%= link_to 'Email author',
              mail_to(post.user.email) %>
</p>
<!-- posts/index.html.erb -->
<%= render :partial => 'post', :collection => @posts %>

<!-- posts/_post.erb -->
<h2><%= post.title %></h2>
<%= format_content post.body %>
<p>
  <%= link_to 'Email author',
              mail_to(post.user.email) %>
</p>
<%= render :partial => @posts %>
<%= render @posts %>
Dynamic Page Titles
<!-- layouts/application.html.erb -->
<head>
  <title>
    Acme Widgets : TX-300 Utility Widget
  </title>
</head>
class PagesController < ApplicationController
  def show
    @widget = Widgets.find(params[:id])
    @title = @widget.name
  end
end

<!-- layouts/application.html.erb -->
<head>
  <title>Acme Widgets : <%= @title %></title>
</head>
This is all View
There is a Helper
<!-- layouts/application.html.erb -->
<head>
  <title>
    Acme Widgets : <%= yield(:title) %>
  </title>
</head>

<!-- widgets/show.html.erb -->
<% content_for :title, @widget.title %>
Default Title
<!-- layouts/application.html.erb -->
<head>
  <title>
    Acme Widgets : <%= yield(:title) || "Home" %>
  </title>
</head>
What else can we use
      this for?
<!-- layouts/application.html.erb -->
<div class="sidebar">
  This is content for the sidebar.
  <%= link_to "Your Account", account_url %>
</div>

<div class="main">
  The main content of the page
</div>
<!-- layouts/application.html.erb -->
<%= yield(:sidebar) %>

<div class="main">
  The main content of the page
</div>

<!-- layouts/application.html.erb -->
<% content_for :sidebar do %>
  <div class="sidebar">
    This is content for the sidebar.
    <%= link_to "Your Account", account_url %>
  </div>
<% end %>
Avoid Duplication
<!-- layouts/application.html.erb -->
<div class="sidebar">
  <%= yield(:sidebar) %>
</div>

<div class="main">
  The main content of the page
</div>

<!-- layouts/application.html.erb -->
<% content_for :sidebar do %>
  This is content for the sidebar.
  <%= link_to "Your Account", account_url %>
<% end %>
Conditional Sidebar
<!-- layouts/application.html.erb -->
<% if content_for?(:sidebar) -%>
  <div class="sidebar">
    <%= yield(:sidebar) %>
  </div>
<% end -%>

<div class="main">
  The main content of the page
</div>

<!-- layouts/application.html.erb -->
<% content_for :sidebar do %>
  This is content for the sidebar.
  <%= link_to "Your Account", account_url %>
<% end %>
Reviews/Refactoring

Mais conteúdo relacionado

Mais procurados

Cucumber Ru09 Web
Cucumber Ru09 WebCucumber Ru09 Web
Cucumber Ru09 WebJoseph Wilk
 
Rails Awesome Email
Rails Awesome EmailRails Awesome Email
Rails Awesome Emailimedo.de
 
SproutCore is Awesome - HTML5 Summer DevFest
SproutCore is Awesome - HTML5 Summer DevFestSproutCore is Awesome - HTML5 Summer DevFest
SproutCore is Awesome - HTML5 Summer DevFesttomdale
 
WordPress maintenance - Keeping it all running smoothly
WordPress maintenance - Keeping it all running smoothlyWordPress maintenance - Keeping it all running smoothly
WordPress maintenance - Keeping it all running smoothlyKelli Wise
 
A different thought angular js part-3
A different thought   angular js part-3A different thought   angular js part-3
A different thought angular js part-3Amit Thakkar
 
Rspec API Documentation
Rspec API DocumentationRspec API Documentation
Rspec API DocumentationSmartLogic
 
NYC Pyladies talk May 2, 2013
NYC Pyladies talk May 2, 2013NYC Pyladies talk May 2, 2013
NYC Pyladies talk May 2, 2013Kat Chuang
 
jQuery Performance Rules
jQuery Performance RulesjQuery Performance Rules
jQuery Performance Rulesnagarajhubli
 
Prezdev parsing & crawling libs
Prezdev parsing & crawling libsPrezdev parsing & crawling libs
Prezdev parsing & crawling libsadrienpad
 
Angular data binding by Soft Solutions4U
Angular data binding by Soft Solutions4UAngular data binding by Soft Solutions4U
Angular data binding by Soft Solutions4Usharsen
 
Haml in 5 minutes
Haml in 5 minutesHaml in 5 minutes
Haml in 5 minutescameronbot
 
Get up and running with google app engine in 60 minutes or less
Get up and running with google app engine in 60 minutes or lessGet up and running with google app engine in 60 minutes or less
Get up and running with google app engine in 60 minutes or lesszrok
 

Mais procurados (19)

Cucumber Ru09 Web
Cucumber Ru09 WebCucumber Ru09 Web
Cucumber Ru09 Web
 
Selenium sandwich-2
Selenium sandwich-2Selenium sandwich-2
Selenium sandwich-2
 
Rails Awesome Email
Rails Awesome EmailRails Awesome Email
Rails Awesome Email
 
SproutCore is Awesome - HTML5 Summer DevFest
SproutCore is Awesome - HTML5 Summer DevFestSproutCore is Awesome - HTML5 Summer DevFest
SproutCore is Awesome - HTML5 Summer DevFest
 
WordPress maintenance - Keeping it all running smoothly
WordPress maintenance - Keeping it all running smoothlyWordPress maintenance - Keeping it all running smoothly
WordPress maintenance - Keeping it all running smoothly
 
Performance
PerformancePerformance
Performance
 
A different thought angular js part-3
A different thought   angular js part-3A different thought   angular js part-3
A different thought angular js part-3
 
Rspec API Documentation
Rspec API DocumentationRspec API Documentation
Rspec API Documentation
 
Merb Router
Merb RouterMerb Router
Merb Router
 
Cucumber testing
Cucumber testingCucumber testing
Cucumber testing
 
NYC Pyladies talk May 2, 2013
NYC Pyladies talk May 2, 2013NYC Pyladies talk May 2, 2013
NYC Pyladies talk May 2, 2013
 
jQuery Performance Rules
jQuery Performance RulesjQuery Performance Rules
jQuery Performance Rules
 
Introduction to JQuery
Introduction to JQueryIntroduction to JQuery
Introduction to JQuery
 
Prezdev parsing & crawling libs
Prezdev parsing & crawling libsPrezdev parsing & crawling libs
Prezdev parsing & crawling libs
 
Angular data binding by Soft Solutions4U
Angular data binding by Soft Solutions4UAngular data binding by Soft Solutions4U
Angular data binding by Soft Solutions4U
 
Haml in 5 minutes
Haml in 5 minutesHaml in 5 minutes
Haml in 5 minutes
 
Get up and running with google app engine in 60 minutes or less
Get up and running with google app engine in 60 minutes or lessGet up and running with google app engine in 60 minutes or less
Get up and running with google app engine in 60 minutes or less
 
Cain & Obenland — Episode 4
Cain & Obenland — Episode 4Cain & Obenland — Episode 4
Cain & Obenland — Episode 4
 
GAEO
GAEOGAEO
GAEO
 

Destaque

Protecting Your Online Persona
Protecting Your Online PersonaProtecting Your Online Persona
Protecting Your Online PersonaJesse Laffen
 
IT Club GTA - Project Management - Introduction
IT Club GTA - Project Management - IntroductionIT Club GTA - Project Management - Introduction
IT Club GTA - Project Management - IntroductionIT Club GTA
 
Mongodb in-anger-boston-rb-2011
Mongodb in-anger-boston-rb-2011Mongodb in-anger-boston-rb-2011
Mongodb in-anger-boston-rb-2011bostonrb
 
Capybara-Webkit
Capybara-WebkitCapybara-Webkit
Capybara-Webkitbostonrb
 
Rspec presentation
Rspec presentationRspec presentation
Rspec presentationMyo T Kyaw
 

Destaque (6)

Protecting Your Online Persona
Protecting Your Online PersonaProtecting Your Online Persona
Protecting Your Online Persona
 
IT Club GTA - Project Management - Introduction
IT Club GTA - Project Management - IntroductionIT Club GTA - Project Management - Introduction
IT Club GTA - Project Management - Introduction
 
Mongodb in-anger-boston-rb-2011
Mongodb in-anger-boston-rb-2011Mongodb in-anger-boston-rb-2011
Mongodb in-anger-boston-rb-2011
 
Capybara-Webkit
Capybara-WebkitCapybara-Webkit
Capybara-Webkit
 
MacRuby
MacRubyMacRuby
MacRuby
 
Rspec presentation
Rspec presentationRspec presentation
Rspec presentation
 

Semelhante a You're Doing It Wrong

Building Cloud Castles
Building Cloud CastlesBuilding Cloud Castles
Building Cloud CastlesBen Scofield
 
Rails 3: Dashing to the Finish
Rails 3: Dashing to the FinishRails 3: Dashing to the Finish
Rails 3: Dashing to the FinishYehuda Katz
 
Turbogears Presentation
Turbogears PresentationTurbogears Presentation
Turbogears Presentationdidip
 
Rails 3 overview
Rails 3 overviewRails 3 overview
Rails 3 overviewYehuda Katz
 
TurboGears2 Pluggable Applications
TurboGears2 Pluggable ApplicationsTurboGears2 Pluggable Applications
TurboGears2 Pluggable ApplicationsAlessandro Molina
 
Desenvolvimento web com Ruby on Rails (parte 2)
Desenvolvimento web com Ruby on Rails (parte 2)Desenvolvimento web com Ruby on Rails (parte 2)
Desenvolvimento web com Ruby on Rails (parte 2)Joao Lucas Santana
 
DRYing Up Rails Views and Controllers
DRYing Up Rails Views and ControllersDRYing Up Rails Views and Controllers
DRYing Up Rails Views and ControllersJames Gray
 
Ruby on Rails - Introduction
Ruby on Rails - IntroductionRuby on Rails - Introduction
Ruby on Rails - IntroductionVagmi Mudumbai
 
OSDC 2009 Rails Turtorial
OSDC 2009 Rails TurtorialOSDC 2009 Rails Turtorial
OSDC 2009 Rails TurtorialYi-Ting Cheng
 
Implement rich snippets in your webshop
Implement rich snippets in your webshopImplement rich snippets in your webshop
Implement rich snippets in your webshopArjen Miedema
 
Use Symfony2 components inside WordPress
Use Symfony2 components inside WordPress Use Symfony2 components inside WordPress
Use Symfony2 components inside WordPress Maurizio Pelizzone
 
Система рендеринга в Magento
Система рендеринга в MagentoСистема рендеринга в Magento
Система рендеринга в MagentoMagecom Ukraine
 
What's new in Rails 2?
What's new in Rails 2?What's new in Rails 2?
What's new in Rails 2?brynary
 
RubyBarCamp “Полезные gems и plugins”
RubyBarCamp “Полезные gems и plugins”RubyBarCamp “Полезные gems и plugins”
RubyBarCamp “Полезные gems и plugins”apostlion
 
Building Potent WordPress Websites
Building Potent WordPress WebsitesBuilding Potent WordPress Websites
Building Potent WordPress WebsitesKyle Cearley
 

Semelhante a You're Doing It Wrong (20)

Mojolicious
MojoliciousMojolicious
Mojolicious
 
Django crush course
Django crush course Django crush course
Django crush course
 
Building Cloud Castles
Building Cloud CastlesBuilding Cloud Castles
Building Cloud Castles
 
Rails 3: Dashing to the Finish
Rails 3: Dashing to the FinishRails 3: Dashing to the Finish
Rails 3: Dashing to the Finish
 
Turbogears Presentation
Turbogears PresentationTurbogears Presentation
Turbogears Presentation
 
Rails 3 overview
Rails 3 overviewRails 3 overview
Rails 3 overview
 
TurboGears2 Pluggable Applications
TurboGears2 Pluggable ApplicationsTurboGears2 Pluggable Applications
TurboGears2 Pluggable Applications
 
Desenvolvimento web com Ruby on Rails (parte 2)
Desenvolvimento web com Ruby on Rails (parte 2)Desenvolvimento web com Ruby on Rails (parte 2)
Desenvolvimento web com Ruby on Rails (parte 2)
 
DRYing Up Rails Views and Controllers
DRYing Up Rails Views and ControllersDRYing Up Rails Views and Controllers
DRYing Up Rails Views and Controllers
 
Ruby on Rails - Introduction
Ruby on Rails - IntroductionRuby on Rails - Introduction
Ruby on Rails - Introduction
 
OSDC 2009 Rails Turtorial
OSDC 2009 Rails TurtorialOSDC 2009 Rails Turtorial
OSDC 2009 Rails Turtorial
 
Implement rich snippets in your webshop
Implement rich snippets in your webshopImplement rich snippets in your webshop
Implement rich snippets in your webshop
 
Bangla html
Bangla htmlBangla html
Bangla html
 
Rails 4.0
Rails 4.0Rails 4.0
Rails 4.0
 
Use Symfony2 components inside WordPress
Use Symfony2 components inside WordPress Use Symfony2 components inside WordPress
Use Symfony2 components inside WordPress
 
Система рендеринга в Magento
Система рендеринга в MagentoСистема рендеринга в Magento
Система рендеринга в Magento
 
What's new in Rails 2?
What's new in Rails 2?What's new in Rails 2?
What's new in Rails 2?
 
RubyBarCamp “Полезные gems и plugins”
RubyBarCamp “Полезные gems и plugins”RubyBarCamp “Полезные gems и plugins”
RubyBarCamp “Полезные gems и plugins”
 
Android L01 - Warm Up
Android L01 - Warm UpAndroid L01 - Warm Up
Android L01 - Warm Up
 
Building Potent WordPress Websites
Building Potent WordPress WebsitesBuilding Potent WordPress Websites
Building Potent WordPress Websites
 

Último

A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?Igalia
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEarley Information Science
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxKatpro Technologies
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)wesley chun
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUK Journal
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024Results
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsJoaquim Jorge
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking MenDelhi Call girls
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 

Último (20)

A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?A Year of the Servo Reboot: Where Are We Now?
A Year of the Servo Reboot: Where Are We Now?
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptxFactors to Consider When Choosing Accounts Payable Services Providers.pptx
Factors to Consider When Choosing Accounts Payable Services Providers.pptx
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)Powerful Google developer tools for immediate impact! (2023-24 C)
Powerful Google developer tools for immediate impact! (2023-24 C)
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024A Call to Action for Generative AI in 2024
A Call to Action for Generative AI in 2024
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
Artificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and MythsArtificial Intelligence: Facts and Myths
Artificial Intelligence: Facts and Myths
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024Tata AIG General Insurance Company - Insurer Innovation Award 2024
Tata AIG General Insurance Company - Insurer Innovation Award 2024
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 

You're Doing It Wrong

  • 1. You’re Doing It Wrong Chad Pytel cpytel@thoughtbot.com @cpytel
  • 2. You’re Doing It Wrong but I love you anyway Chad Pytel cpytel@thoughtbot.com @cpytel
  • 5. What makes them hard to test? • Scripts that live outside app • Often have network and file access • Often have output
  • 6. Example Task namespace :twitter do task :search => :environment do puts "Searching twitter." Twitter.search("@cpytel").each do |result| puts "Processing #{result.inspect}." alert = Alert.create(:body => result) alert.save_cache_file! end end puts "All done!" end
  • 8. context "rake twitter:search" do setup do # How slow is this going to be? Very. @out = `cd #{Rails.root} && rake twitter:search 2>&1` end
  • 9. should "print a message at the beginning" do assert_match /Searching/i, @out end
  • 10. should "find all tweets containing @cpytel" do # this one would be based entirely on luck. end
  • 11. This Has Problems • Slow • No mocking or stubbing available • Task isn’t in a transaction
  • 13. How do we fix this?
  • 14. Rake tasks are just Ruby
  • 15. Move it all into the Model
  • 16. class Alert < ActiveRecord::Base def self.create_all_from_twitter_search(output = $stdout) output.puts "Searching twitter." Twitter.search("@cpytel").each do |result| output.puts "Processing #{result.inspect}." alert = create(:body => result) alert.save_cache_file! end output.puts "All done!" end def save_cache_file! # Removes a file from the filesystem. end end
  • 17. The Task is Nice and Skinny namespace :twitter do task :search => :environment do Alert.create_all_from_twitter_search end end
  • 18. Testing is Pretty Normal # test/unit/alert_test.rb class AlertTest < ActiveSupport::TestCase context "create_all_from_twitter_search" do setup do # Make sure none of the tests below hit the # network or touch the filesystem. Alert.any_instance.stubs(:save_cache_file!) Twitter.stubs(:search).returns([]) @output = StringIO.new end
  • 19. should "print a message at the beginning" do Alert.create_all_from_twitter_search(@output) assert_match /Searching/i, @output.string end
  • 20. should "save some cache files" do Twitter.stubs(:search).returns(["one"]) alert = mock("alert") alert.expects(:save_cache_file!) Alert.stubs(:create).returns(alert) Alert.create_all_from_twitter_search(@output) end
  • 21. should "find all tweets containing @cpytel" do Twitter.expects(:search). with("@cpytel"). returns(["body"]) Alert.create_all_from_twitter_search(@output) end
  • 22. We can mock and stub!
  • 23. We can use normal tools! • FakeWeb/WebMock • FileUtils::NoWrite
  • 24. In Summary • You can test drive development of your rake tasks • Rake tasks should live inside a model (or class)
  • 25. Views
  • 27. Know How They Change
  • 28. # Edit form <%= form_for :user, :url => user_path(@user), :html => {:method => :put} do |form| %>
  • 29. <%= form_for @user do |form| %>
  • 30. <!-- posts/index.html.erb --> <% @posts.each do |post| -%> <h2><%= post.title %></h2> <%= format_content post.body %> <p> <%= link_to 'Email author', mail_to(post.user.email) %> </p> <% end -%>
  • 31. Move the post content into a partial
  • 32. <!-- posts/index.html.erb --> <% @posts.each do |post| -%> <%= render :partial => 'post', :object => :post %> <% end -%> <!-- posts/_post.erb --> <h2><%= post.title %></h2> <%= format_content post.body %> <p><%= link_to 'Email author', mail_to(post.user.email) %></p>
  • 33. Looping was built into render
  • 34. <!-- posts/index.html.erb --> <%= render :partial => 'post', :collection => @posts %> <!-- posts/_post.erb --> <h2><%= post.title %></h2> <%= format_content post.body %> <p> <%= link_to 'Email author', mail_to(post.user.email) %> </p>
  • 35. <!-- posts/index.html.erb --> <%= render :partial => 'post', :collection => @posts %> <!-- posts/_post.erb --> <h2><%= post.title %></h2> <%= format_content post.body %> <p> <%= link_to 'Email author', mail_to(post.user.email) %> </p>
  • 36. <%= render :partial => @posts %>
  • 39. <!-- layouts/application.html.erb --> <head> <title> Acme Widgets : TX-300 Utility Widget </title> </head>
  • 40. class PagesController < ApplicationController def show @widget = Widgets.find(params[:id]) @title = @widget.name end end <!-- layouts/application.html.erb --> <head> <title>Acme Widgets : <%= @title %></title> </head>
  • 41. This is all View
  • 42. There is a Helper
  • 43. <!-- layouts/application.html.erb --> <head> <title> Acme Widgets : <%= yield(:title) %> </title> </head> <!-- widgets/show.html.erb --> <% content_for :title, @widget.title %>
  • 45. <!-- layouts/application.html.erb --> <head> <title> Acme Widgets : <%= yield(:title) || "Home" %> </title> </head>
  • 46. What else can we use this for?
  • 47. <!-- layouts/application.html.erb --> <div class="sidebar"> This is content for the sidebar. <%= link_to "Your Account", account_url %> </div> <div class="main"> The main content of the page </div>
  • 48. <!-- layouts/application.html.erb --> <%= yield(:sidebar) %> <div class="main"> The main content of the page </div> <!-- layouts/application.html.erb --> <% content_for :sidebar do %> <div class="sidebar"> This is content for the sidebar. <%= link_to "Your Account", account_url %> </div> <% end %>
  • 50. <!-- layouts/application.html.erb --> <div class="sidebar"> <%= yield(:sidebar) %> </div> <div class="main"> The main content of the page </div> <!-- layouts/application.html.erb --> <% content_for :sidebar do %> This is content for the sidebar. <%= link_to "Your Account", account_url %> <% end %>
  • 51. Conditional Sidebar <!-- layouts/application.html.erb --> <% if content_for?(:sidebar) -%> <div class="sidebar"> <%= yield(:sidebar) %> </div> <% end -%> <div class="main"> The main content of the page </div> <!-- layouts/application.html.erb --> <% content_for :sidebar do %> This is content for the sidebar. <%= link_to "Your Account", account_url %> <% end %>
  • 52.

Notas do Editor

  1. \n
  2. \n
  3. \n
  4. \n
  5. \n
  6. \n
  7. \n
  8. \n
  9. \n
  10. \n
  11. \n
  12. \n
  13. \n
  14. \n
  15. \n
  16. \n
  17. \n
  18. \n
  19. \n
  20. \n
  21. \n
  22. \n
  23. \n
  24. \n
  25. \n
  26. \n
  27. \n
  28. \n
  29. \n
  30. \n
  31. \n
  32. \n
  33. \n
  34. \n
  35. \n
  36. \n
  37. \n
  38. \n
  39. \n
  40. \n
  41. \n
  42. \n
  43. \n
  44. \n
  45. \n
  46. \n
  47. \n
  48. \n
  49. \n
  50. \n
  51. \n
  52. \n
  53. \n