SlideShare a Scribd company logo
1 of 168
Download to read offline
Pruebas BDD de
      Aceptación con Ruby
                   Sergio Gil y Luismi Cavallé




Agile Spain 2010
Historias de Usuario
[A story] has to be a description of a
requirement and its business benefit,
 and a set of criteria by which we all
        agree that it is “done”


                       – Dan North


                             http://blog.dannorth.net/whats-in-a-story/
Anatomía de una historia
Feature: Serve coffee
  In order to earn money
  Customers should be able to
  buy coffee at all times



  Scenario: Buy last coffee
    Given there are 1 coffees left in the machine
    And I have deposited 1$
    When I press the coffee button
    Then I should be served a coffee
Anatomía de una historia
    Feature: Serve coffee
      In order to earn money             Narrativa
      Customers should be able to
      buy coffee at all times



      Scenario: Buy last coffee
        Given there are 1 coffees left in the machine
        And I have deposited 1$
        When I press the coffee button
        Then I should be served a coffee


Criterio de Aceptación
Narrativa

Feature: Serve coffee
 In order to earn money
 Customers should be able to
 buy coffee at all times
Narrativa
                          Título

Feature: Serve coffee
 In order to earn money
 Customers should be able to
 buy coffee at all times
Narrativa

     Feature: Serve coffee
          In order to earn money
          Customers should be able to

  Rol     buy coffee at all times
¿Quién?
Narrativa

Feature: Serve coffee
 In order to earn money
 Customers should be able to
 buy coffee at all times

                           Funcionalidad
                              ¿Qué?
Narrativa

                           Beneficio
Feature: Serve coffee
                           ¿Por qué?
 In order to earn money
 Customers should be able to
 buy coffee at all times
Regla de los 5 porqués
Regla de los 5 porqués

             ENSÉÑAME LA
               PASTA !!!!
Criterio de Aceptación

Scenario: Buy last coffee

 Given there are 1 coffees left in the machine
 And I have deposited 1$

 When I press the coffee button

 Then I should be served a coffee
Criterio de Aceptación
                                    Contexto
Scenario: Buy last coffee

 Given there are 1 coffees left in the machine
 And I have deposited 1$

 When I press the coffee button

 Then I should be served a coffee
Criterio de Aceptación

Scenario: Buy last coffee

 Given there are 1 coffees left in the machine
 And I have deposited 1$
                                       Eventos
 When I press the coffee button

 Then I should be served a coffee
Criterio de Aceptación

Scenario: Buy last coffee

 Given there are 1 coffees left in the machine
 And I have deposited 1$

 When I press the coffee button
                                       Resultados
 Then I should be served a coffee
Criterio de Aceptación

Scenario: Buy last coffee

 Given there are 1 coffees left in the machine
 And I have deposited 1$

 When I press the coffee button




                              NE
 Then I should be served a coffee



                             O
                            D
Beneficio para el negocio
Programadores              Testers




Analistas       Clientes   Managers
Beneficio para el negocio
Programadores                                      Testers



              Historia de Usuario
            Token de comunicación / discusión
            Priorización según beneficio / valor
              Criterio común de “terminado”




Analistas                Clientes                  Managers
Cucumber
Cucumber
Feature: Serve coffee
  In order to earn money
  Customers should be able to
  buy coffee at all times

Scenario: Buy last coffee
  Given there are 1 coffees left in the machine
  And I have deposited 1$
  When I press the coffee button
  Then I should be served a coffee
Pasos
Given a user “john” with password “secret”



    When he tries to login as “james”



    Then he should see an error message
Definición de pasos
Given a user “john” with password “secret”
Definición de pasos
   Given a user “john” with password “secret”



Given /^a user "(.+)" with password "(.+)"$/ do |login, password|
Definición de pasos
      Given a user “john” with password “secret”



Given /^a user "(.+)" with password "(.+)"$/ do |login, password|
  User.create! :login => login, :password => password
end
Definición de pasos
When he tries to login as “james”
Definición de pasos
    When he tries to login as “james”



When /^he tries to login as "(.+)"$/ do |login|
Definición de pasos
    When he tries to login as “james”



When /^he tries to login as "(.+)"$/ do |login|
  visit "/login"
  fill_in "Username", :with => login
  fill_in "Password", :with => "secret"
  click_button "Login"
end
Definición de pasos
Then he should see an error message
Definición de pasos
     Then he should see an error message




Then /^I should see an error message$/ do
Definición de pasos
     Then he should see an error message




Then /^I should see an error message$/ do
  assert page.has_content?("Invalid credentials")
end
Demo
http://vimeo.com/12441999
+40 Idiomas
# language: es
Característica: Búsqueda de cursos
  Para asegurar el mejor uso de los cursos
  Los estudiantes potenciales
  deberían poder buscar cursos

  Escenario: Búsqueda por materia
    Dado que hay 240 cursos, ninguno sobre "biología"
    Y hay 2 cursos A001, B205 sobre "biología"

    Cuando busco por "biología"

    Entonces debería ver los siguientes cursos:
      | Código de curso |
      | A001            |
      | B205            |
Otros lenguajes
package cukes;

import cuke4duke.Given;
import java.util.List;
import java.util.ArrayList;

public class BellySteps {
    private List<String> belly = new ArrayList<String>();

    @Given("I have (d+) cukes in my belly")
    public void bellyCukes(int cukes) {
        for(int i = 0; i < cukes; i++) {
            belly.add("cuke " + i);
        }
    }
}
Otros lenguajes
package cukes;

import cuke4duke.Given;
import java.util.List;
import java.util.ArrayList;

public class BellySteps {
    private List<String> belly = new ArrayList<String>();

    @Given("I have (d+) cukes in my belly")
    public void bellyCukes(int cukes) {
        for(int i = 0; i < cukes; i++) {
            belly.add("cuke " + i);
        }
    }
}




(Given #"^I have entered ([d.]+) into the calculator$"
  (fn [number]
    (push-number (Float. number))))
Más funcionalidades...
Background
Feature: Multiple blog support

  Background:
    Given a global administrator named "Greg"
    And a blog named "Greg's anti-tax rants"
    And a customer named "Dr. Bill"
    And a blog named "Expensive Therapy" owned by "Dr. Bill"

  Scenario: Dr. Bill posts to his own blog

  Scenario: Dr. Bill tries to post to somebody else's blog

  Scenario: Greg posts to a client's blog
Tags
  @billing
  Feature: Verify billing

    @important
    Scenario: Missing product description

    Scenario: Several products




$ cucumber --tags @billing,~@important
Hooks
Before do
  @browser = Browser.new
end

After do
  @browser.close
end
Hooks
Before do
  @browser = Browser.new   Around do |scenario, block|
end                          Timeout.timeout(3) do
                               block.call
After do                     end
  @browser.close           end
end
Hooks
Before do
  @browser = Browser.new    Around do |scenario, block|
end                           Timeout.timeout(3) do
                                block.call
After do                      end
  @browser.close            end
end




                     Before('@foo')

                     After('~@bar')
Scenario Outline

Scenario Outline: eating
  Given there are <start> cucumbers
  When I eat <eat> cucumbers
  Then I should have <left> cucumbers

  Examples:
    | start | eat | left |
    | 12    | 5 | 7      |
    | 20    | 5 | 15 |
So far, so good?
• Historias de Usuario
• Beneficio para el negocio
• Cucumber
So far, so good?
• Historias de Usuario
• Beneficio para el negocio
• Cucumber

  Coming next...
• Testing de aceptación Web
• Beneficio para los devs
• Alternativas a Cucumber
Aceptación para Web:
     Capybara
DSL de interacción web
(navegador programático)
Usa el lenguaje del usuario

   class
  method
GET / POST
parameters
Usa el lenguaje del usuario

   class           page
  method           URL
GET / POST          link
parameters         form
visit "/wadus"
BDD de Aceptación con Ruby
click_link "Add article"
click_link "Add article"
click "Add article"
BDD de Aceptación con Ruby
fill_in "Title", :with => "Wadus"
fill_in "Title", :with => "Wadus"
choose "Option"
fill_in "Title", :with => "Wadus"
choose "Option"
check "Option"
fill_in "Title", :with => "Wadus"
choose "Option"
check "Option"
uncheck "Option"
fill_in "Title", :with => "Wadus"
choose "Option"
check "Option"
uncheck "Option"
select "1980", :from => "Birth Year"
fill_in "Title", :with => "Wadus"
choose "Option"
check "Option"
uncheck "Option"
select "1980", :from => "Birth Year"
click_button "Save"
fill_in "Title", :with => "Wadus"
choose "Option"
check "Option"
uncheck "Option"
select "1980", :from => "Birth Year"
click_button "Save"
click "Save"
within :css, ".article:first" do
  click_link "Edit"
end
Matchers
page.should have_content("Wadus")
page.should have_content("Wadus")
page.should_not have_content("Wadus")
page.should have_content("Wadus")
page.should_not have_content("Wadus")

page.should have_css(".article", :text => "Wadus")
page.should have_content("Wadus")
page.should_not have_content("Wadus")

page.should have_css(".article", :text => "Wadus")
page.should have_css(".article", :count => 3)
page.should have_content("Wadus")
page.should_not have_content("Wadus")

page.should have_css(".article", :text => "Wadus")
page.should have_css(".article", :count => 3)

page.should have_xpath("//*[@class='article']")
page.should have_css(".article", :text => "Wadus") do |article|
  article.should have_css(".author", :text => "@porras")
  article.should have_css(".links") do |links|
    links.should have_css("a", :href => "http://wadus.info")
    links.should have_css("a", :href => "http://bit.ly/wadus")
  end
end
save_and_open_page
Drivers
RackTest
RackTest
Basado en Rack
RackTest
Basado en Rack


    FAST!
RackTest
Basado en Rack


    FAST!
Sin Javascript
RackTest
Basado en Rack


    FAST!
Sin Javascript
 No es ‘real’
Selenium
Selenium
Basado en browsers programables
Selenium
Basado en browsers programables


          Javascript
Selenium
Basado en browsers programables


          Javascript
        Aceptación pura
Selenium
Basado en browsers programables


          Javascript
        Aceptación pura
           ¡LENTO!
Selenium
Basado en browsers programables


          Javascript
        Aceptación pura
           ¡LENTO!
         Un poco frágil
Selenium
Basado en browsers programables


          Javascript
        Aceptación pura
           ¡LENTO!
         Un poco frágil
             Java
Celerity / Culerity
Celerity / Culerity
   Basado en HTMLUnit
Celerity / Culerity
   Basado en HTMLUnit


       Javascript
Celerity / Culerity
   Basado en HTMLUnit


       Javascript
   Aceptación casi pura
Celerity / Culerity
   Basado en HTMLUnit


       Javascript
   Aceptación casi pura
      No muy lento
Celerity / Culerity
   Basado en HTMLUnit


       Javascript
   Aceptación casi pura
      No muy lento
          Java
Envjs
Envjs
Basado en SpiderMonkey
Envjs
Basado en SpiderMonkey


      Javascript
Envjs
Basado en SpiderMonkey


      Javascript
  Aceptación casi pura
Envjs
Basado en SpiderMonkey


      Javascript
  Aceptación casi pura
     No muy lento
Envjs
Basado en SpiderMonkey


      Javascript
  Aceptación casi pura
     No muy lento
         Ruby
Envjs
Basado en SpiderMonkey


      Javascript
  Aceptación casi pura
     No muy lento
         Ruby
    Un poco verde
RackTest




Selenium




 Culerity



            0   37.5   75.0   112.5   150.0
Valor para el
desarrollador
Excelente herramienta
   de verificación
Pero TDD no es QA
Pero TDD no es QA
             sólo
Dirige el desarrollo
“Outside-in testing is the best
way to avoid overengineering”



                    http://www.sarahmei.com/blog/2010/05/29/outside-in-bdd/
Up-front
Up-front




   M
Up-front




   C

   M
Up-front



   V

   C

   M
Up-front

   T

   V

   C

   M
Up-front

   T
           T

   V

   C

   M
Up-front

       T
T              T

       V

       C

       M
Outside-in
Outside-in

    F
Outside-in

    F


    V
Outside-in

    F


    V
    C
Outside-in

    F


    V
    C
    M
Outside-in

                     F
    F                            F

                 V           V
         V
F




                                     F
             C C C
    V




                                 V
        C



                             C
                     MM
                 M       M
             M
“Tu interfaz es tu producto”




                   http://gettingreal.37signals.com/ch09_Interface_First.php
Permite otras prácticas
        ágiles
The Simplest Thing That
  Could Possibly Work
Dejar que el diseño “emerja”
Pair Programming
Refactorización contínua
Integración Contínua
Propiedad colectiva del código
Release Often
Continuous Deployment
Steak
A veces Cucumber
(historias en texto plano)
  no es la mejor opción
Todo el “valor para el
desarrollador” sin la
  burocracia extra
feature "Main page" do

 background do
   create_user :login => "wadus"
 end

 scenario "should show existing books" do
   create_book :title => "The Pragmatic Programmer"

      login_as "wadus"
      visit "/"

   page.should have_css(".book", :text => "The Pragmatic Programmer")
 end

end
feature "Main page" do

 background do
   create_user :login => "wadus"
 end

 scenario "should show existing books" do
   create_book :title => "The Pragmatic Programmer"

      login_as "wadus"
      visit "/"

   page.should have_css(".book", :text => "The Pragmatic Programmer")
 end

end
feature "Main page" do

 background do
   create_user :login => "wadus"
 end

 scenario "should show existing books" do
   create_book :title => "The Pragmatic Programmer"

      login_as "wadus"
      visit "/"

   page.should have_css(".book", :text => "The Pragmatic Programmer")
 end

end
feature "Main page" do

 background do
   create_user :login => "wadus"
 end

 scenario "should show existing books" do
   create_book :title => "The Pragmatic Programmer"

      login_as "wadus"
      visit "/"

   page.should have_css(".book", :text => "The Pragmatic Programmer")
 end

end
feature "Main page" do

 background do
   create_user :login => "wadus"
 end

 scenario "should show existing books" do
   create_book :title => "The Pragmatic Programmer"

      login_as "wadus"
      visit "/"

   page.should have_css(".book", :text => "The Pragmatic Programmer")
 end

end
feature "Main page" do

 background do
   create_user :login => "wadus"
 end

 scenario "should show existing books" do
   create_book :title => "The Pragmatic Programmer"

      login_as "wadus"
      visit "/"

   page.should have_css(".book", :text => "The Pragmatic Programmer")
 end

end
feature "Main page" do

 background do
   create_user :login => "wadus"
 end

 scenario "should show existing books" do
   create_book :title => "The Pragmatic Programmer"

      login_as "wadus"
      visit "/"

   page.should have_css(".book", :text => "The Pragmatic Programmer")
 end

end
Demo
http://vimeo.com/12468092
Más amigos
Spork
Spork

Sin spork


Con spork


            0    3.25 6.50   9.75 13.00
Factorías
BDD de Aceptación con Ruby
fixture_replacement
fixture_replacement
   factory_girl
fixture_replacement
   factory_girl
     machinist
fixture_replacement
   factory_girl
     machinist
      fixjour
fixture_replacement
   factory_girl
     machinist
      fixjour
      cranky
fixture_replacement
   factory_girl
     machinist
      fixjour
      cranky
        Ruby
module Factories

 def create_user(attrs = {})
   attrs = attrs.dup
   attrs[:name] ||= String.random(10)
   attrs[:email] ||= "#{String.random(10)}@example.com"
   User.create!(attrs)
 end

 def create_article(attrs = {})
   attrs = attrs.dup
   attrs[:title] ||= String.random(10)
   attrs[:author] ||= create_user
   Article.create!(attrs)
 end

end

...

create_user
create_user(:name => "Bartolo")
create_article
create_article(:author => create_user(:name => "Mr. Wadus"))
Delorean
Delorean
Delorean

it "should show latest created user" do
  time_travel_to(3.minutes.ago) { create_user :name => "John" }
  time_travel_to(5.minutes.ago) { create_user :name => "Chris" }

 get '/'

  page.should have_content("John")
  page.should_not have_content("Chris")
end
Database Cleaner
Database Cleaner


DatabaseCleaner.strategy = :truncation
DatabaseCleaner.clean
Database Cleaner


DatabaseCleaner.strategy = :transaction
DatabaseCleaner.clean
Email Spec
Email Spec

mailbox_for("porras@example.com").should have(1).email

open_email "porras@example.com"

current_email.should have_subject("Bienvenido a Wadus 2.0")
current_email.should have_text("Hola, porras")
Webmock
Webmock


request(:post, "www.example.com").
                with(:body => "abc").
                should have_been_made.once
MundoPepino
“MundoPepino es un conjunto de
pasos genéricos para testear una
   aplicación Rails utilizando
           Cucumber”
Dado que tenemos un huerto
Y una huerta
Y un huerto "En el río"
Y una huerta "En el castro"
Y un huerto llamado "Regadío"
Y una huerta llamada "Secano"
Y 2 huertos
Y 2 huertos "Regadío"
Y 2 huertos llamados "Secano"
Y 2 huertas llamadas "Secano"
Y 3 huertas llamadas "H-01, H-02 y H-03"
Entonces tenemos en bbdd 17 huertos
Y tenemos en bbdd un huerto "En el río"
Y tenemos en bbdd una huerta "En el castro"
Y tenemos en bbdd 3 huertos "Regadío"
Y tenemos en bbdd 5 huertas "Secano"
Y tenemos en bbdd un huerto "H-01"
Y tenemos en bbdd un huerto "H-02"
Y tenemos en bbdd un huerto "H-03"
Cuando visito   la página de creación de huerto
Entonces debo   ver la etiqueta H2 con el valor "Alta de Huerta"
Cuando visito   la página de alta de huerto
Entonces debo   ver la etiqueta H2 con el valor "Alta de Huerta"
Cuando visito   la página de nueva huerta
Entonces debo   ver la etiqueta H2 con el valor "Alta de Huerta"

Dado que visito la página de creación de huerto
Entonces debo ver la etiqueta H2 con el valor "Alta de Huerta"
Dado que tenemos un huerto llamado "H-01"
Y que dicho huerto tiene los siguientes aspersores:
| nombre | caudal | unidad caudal |
| A-01 |      15 | m3             |
| A-02 |      12 | m3             |
| B-01 |      10 | m3             |
Entonces tenemos en bbdd un huerto
Y tenemos en bbdd tres aspersores
Y el huerto "H-01" tiene en bbdd un aspersor "A-01"
Y el aspersor "A-01" tiene en bbdd como caudal "15"
Y tiene en bbdd como unidad caudal "m3"
Y el huerto "H-01" tiene en bbdd un aspersor "A-02"
Y el aspersor "A-02" tiene en bbdd como caudal "12"
Y tiene en bbdd como unidad caudal "m3"
Y el huerto "H-01" tiene en bbdd un aspersor "B-01"
Y el aspersor "B-01" tiene en bbdd como caudal "10"
Y tiene en bbdd como unidad caudal "m3"
Recapitulando
• Aceptación Web
• Valor para los devs
• Steak (‘cause Cucumber
  is for veggies)
• Otros amiguitos...
Gracias!
Gracias!
                   @porras y @cavalle



                   ¿Preg untas?


Agile Spain 2010

More Related Content

Featured

PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024Neil Kimberley
 
Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)contently
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024Albert Qian
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsKurio // The Social Media Age(ncy)
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Search Engine Journal
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summarySpeakerHub
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next Tessa Mero
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentLily Ray
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best PracticesVit Horky
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project managementMindGenius
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...RachelPearson36
 
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...Applitools
 
12 Ways to Increase Your Influence at Work
12 Ways to Increase Your Influence at Work12 Ways to Increase Your Influence at Work
12 Ways to Increase Your Influence at WorkGetSmarter
 
Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...
Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...
Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...DevGAMM Conference
 

Featured (20)

Skeleton Culture Code
Skeleton Culture CodeSkeleton Culture Code
Skeleton Culture Code
 
PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024PEPSICO Presentation to CAGNY Conference Feb 2024
PEPSICO Presentation to CAGNY Conference Feb 2024
 
Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)Content Methodology: A Best Practices Report (Webinar)
Content Methodology: A Best Practices Report (Webinar)
 
How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024How to Prepare For a Successful Job Search for 2024
How to Prepare For a Successful Job Search for 2024
 
Social Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie InsightsSocial Media Marketing Trends 2024 // The Global Indie Insights
Social Media Marketing Trends 2024 // The Global Indie Insights
 
Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024Trends In Paid Search: Navigating The Digital Landscape In 2024
Trends In Paid Search: Navigating The Digital Landscape In 2024
 
5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary5 Public speaking tips from TED - Visualized summary
5 Public speaking tips from TED - Visualized summary
 
ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd ChatGPT and the Future of Work - Clark Boyd
ChatGPT and the Future of Work - Clark Boyd
 
Getting into the tech field. what next
Getting into the tech field. what next Getting into the tech field. what next
Getting into the tech field. what next
 
Google's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search IntentGoogle's Just Not That Into You: Understanding Core Updates & Search Intent
Google's Just Not That Into You: Understanding Core Updates & Search Intent
 
How to have difficult conversations
How to have difficult conversations How to have difficult conversations
How to have difficult conversations
 
Introduction to Data Science
Introduction to Data ScienceIntroduction to Data Science
Introduction to Data Science
 
Time Management & Productivity - Best Practices
Time Management & Productivity -  Best PracticesTime Management & Productivity -  Best Practices
Time Management & Productivity - Best Practices
 
The six step guide to practical project management
The six step guide to practical project managementThe six step guide to practical project management
The six step guide to practical project management
 
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
Beginners Guide to TikTok for Search - Rachel Pearson - We are Tilt __ Bright...
 
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
Unlocking the Power of ChatGPT and AI in Testing - A Real-World Look, present...
 
12 Ways to Increase Your Influence at Work
12 Ways to Increase Your Influence at Work12 Ways to Increase Your Influence at Work
12 Ways to Increase Your Influence at Work
 
ChatGPT webinar slides
ChatGPT webinar slidesChatGPT webinar slides
ChatGPT webinar slides
 
More than Just Lines on a Map: Best Practices for U.S Bike Routes
More than Just Lines on a Map: Best Practices for U.S Bike RoutesMore than Just Lines on a Map: Best Practices for U.S Bike Routes
More than Just Lines on a Map: Best Practices for U.S Bike Routes
 
Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...
Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...
Ride the Storm: Navigating Through Unstable Periods / Katerina Rudko (Belka G...
 

BDD de Aceptación con Ruby