SlideShare une entreprise Scribd logo
1  sur  92
Testing C# and ASP.net using Ruby Meerkatalyst @Ben_HallBen@BenHall.me.ukBlog.BenHall.me.ukCodeBetter.com/blogs/benhall
London based C# MVPWeb Developer @ 7digital.com Working on a number of Open Source Projects Co-Author of  Testing ASP.net Web Applications http://www.testingaspnet.com
Outside-in development UI level testing Cucumber Object level testing using RSpec
WHY? http://www.flickr.com/photos/atomicpuppy/2132073976/
VALUE
State of .NET today
Realised Ruby doesn’t have as many problems as .net
Innovation
Outside-in Development
Behaviour Driven Development Cucumber, RSpec and many others
Direct communication with customers
Focus
UI Testing is not hard... Unless you make an effort
What does this do? [Test]public void WatiNSearchText_SearchWatiN_TextDisplayedOnScreen(){    IE ie = new IE("http://localhost:49992/WatiNSite/");    ie.TextField(Find.ByName(“q")).TypeText("WatiN");    ie.Button(Find.ByValue("Search")).Click();    bool result = ie.Text.Contains("WatiN");    Assert.IsTrue(result); }
WebRat http://www.flickr.com/photos/whatwhat/22624256/
visit click_link fill_in click_button check and uncheck choose select attach_file
visit ‘http://localhost’
Reduce Ceremony
visit ‘http://www.google.com’ fill_in :q, :with => ‘asp.net’ click_button ‘Google Search’ response_body.should contain(‘Microsoft’)
Design UI for testability Outside-in development encourages this
DATA! http://www.flickr.com/photos/gagilas/2659695352/
Hard and Important Production data in dev anyone?
Active Record and SQL Server Order.create
class Order < ActiveRecord::Base set_primary_key :OrderID has_many :OrderItem has_one  :OrderStatus,              :primary_key => "OrderStatusID",              :foreign_key => "OrderStatusID" belongs_to :Customer,                   :primary_key => "UserName",                   :foreign_key => "UserName"   def self.create()     order = Order.new (:modified_on => DateTime.now,                                          :created_on => DateTime.now,                                           :order_id => Guid.new.to_s) order.OrderStatusID = OrderStatus.find_or_create order.Customer = Customer.find_or_create(Faker::Internet.user_name) order.save!     return order   end end Legacy Database Looking at auto-generating model for testing
Test Data Builders ProductCatalogBuilder           .create(10.products)           .for_shop(123)         Customer         .create(“Bob”)         .owning(10.products)         .with_credit_card(CreditCard.create)         .with_address(Address.create)
Customer.find_or_create(Faker::Internet.user_name) >>> Faker::Internet.user_name ,[object Object],>>> Faker::Internet.user_name ,[object Object],>>> Faker::Internet.user_name => "nicolette.nitzsche" >>> Faker::Internet.email ,[object Object],>>> Faker::Name.name => "Murray Hermiston"
2 rules of data generation Always insert Always clean up
We still need to write the tests in a successful manner
Cucumber http://www.flickr.com/photos/vizzzual-dot-com/2738586453/
Feature:Search Google In order to find information As a researcher I want to search google    Scenario: Searching for a valid term GivenI visit "http://www.google.com/"     WhenI enter a search for "asp.net"     AndI click the "Google Search" button     ThenI should see the first result "The Official Microsoft ASP.NET Site"
Given /^I visit "([^quot;]*)"$/ do |website|   visit website end   When /^I enter a search for "([^quot;]*)"$/ do |term|   fill_in :q, :with => term end   When /^I click the "([^quot;]*)" button$/ do |button|   click_button button end   Then /^I should see the first result "([^quot;]*)"$/ do |result|   response_body.should contain(result) end
Thanks to TekPub for Kona sample
Thanks to TekPub for Kona sample
Feature: Display Products   In order to browse the catalog   The customer   Needs to see products Scenario: Single featured product on homepage     Given the featured product "Adventure Works 20x30 Binoculars"     When I visit the homepage     Then I should see "Adventure Works 20x30 Binoculars" listed under "Featured"
Given /^the featured product "([^quot;]*)"$/ do |product_name| Product.createproduct_name, ‘featured’ end
When /^I visit the homepage$/ do visit url + '/' end
“Designed” UI for Testability Then /^I should see "([^quot;]*)" listed under "([^quot;]*)"$/ do |product, area|   within div_id(area) do |products| products.should contain(product)   end End def div_id(area)   "#" + area.downcase.underscore end
Using a ‘real’ framework Unit testing frameworks for UI testing? Really?!
Before do open_connection empty_database end at_exit do empty_database End def empty_database date_of_last_restore = '01/01/2010' OrderItem.delete_all["DateAdded > ?", date_of_last_restore] Order.delete_all["CreatedOn > ?", date_of_last_restore] end Multiple Hooks
require 'cucumber_screenshot' After do |scenario|    screenshot if scenario.failed? end AfterStep('@screenshot') do |scenario|    screenshot if screenshot_due?  end
def url   "http://www.website.local" end Webrat.configure do |config| config.mode = :selenium config.application_framework = :external end env_selenium.rb
Webrat.configure do |config| config.mode = :selenium config.application_framework = :external config.selenium_browser_key = get_browser_key end def get_browser_key()   command = "*firefox"   command = ENV['BROWSER'] if ENV['BROWSER']   return command end env_selenium.rb
cucumber --profile selenium browser=*firefox cucumber --profile selenium browser=*safari cucumber --profile selenium browser=*iexplore cucumber --profile selenium browser=*googlechrome
env_headless.rb Webrat.configure do |config|   config.mode = :mechanize end cucumber --profile webrat
ANTI-PATTERNS http://www.flickr.com/photos/gagilas/2659695352/
Noisy, repeated scenarios Scenario: Blowout Specials     Given "Cascade Fur-lined Hiking Boots" in "Blowout Specials"     When I visit the homepage     Then I should see "Cascade Fur-lined Hiking Boots" listed under "Blowout Specials“ Scenario: Blowout Specials     Given " Trailhead Locking Carabiner " in "Blowout Specials"     When I visit the homepage     Then I should see "Trailhead Locking Carabiner " listed under "Blowout Specials" Scenario: Blowout Specials     Given " Climbing Rope with Single Caribiner " in "Blowout Specials"     When I visit the homepage     Then I should see " Climbing Rope with Single Caribiner " listed under "Blowout Specials"
Single scenario, multiple examples Scenario Outline: Blowout Specials     Given <product> in "Blowout Specials"     When I visit the homepage     Then I should see <product> listed under "Blowout Specials"     Examples:       | product                                                         |       |  "Cascade Fur-lined Hiking Boots"           |       |  "Trailhead Locking Carabiner"                 |       |  "Climbing Rope with Single Caribiner"   |
Long scenarios When I go to the "Checkout" page And I enter “Mr A. Nonymous ” in “Card Name” textbox And I enter “1111111111111111” in “Card Number” textbox And I enter “GU1 2PE” in “Card Post Code” textbox And I select “01” in “Card Start Month” textbox And I select “09” in “Card Start Year” textbox And I select “01” in “Card End Month” textbox And I select “19” in “Card End Year” textbox And I enter “123” in “Card Validation” textbox And I click the "Pay with Card (Add Card)" button Then I should be on the "Download" page
When I go to the "Checkout" page And I enter a new credit card:        | type        | field                         | value                            |        | textbox   | Card Name            | Mr A. Nonymous       |        | textbox   | Card Number        | 4444333322221111 |        | textbox   | Card Post Code     | GU1 2PE                      |        | select      | Card Start Month | 01                                 |        | select      | Card Start Year      | 09                                 |        | select      | Card End Month   | 01                                 |        | select      | Card End Year        | 19                                 |        | textbox   | Card Validation      | 123                              | And I click the "Pay with Card (Add Card)" button Then I should be on the "Download" page
Clear, re-useable, readable When I go to the "Checkout" page And I enter a valid credit card  And I click the "Pay with Card (Add Card)" button Then I should be on the "Download" page
Implementation details in steps When I go to the "Checkout" page And I enter “Mr A. Nonymous ” in “Card Name” textbox And I enter “1111111111111111” in “Card Number” textbox And I enter “GU1 2PE” in “Card Post Code” textbox And I select “01” in “Card Start Month” textbox And I select “09” in “Card Start Year” textbox And I select “01” in “Card End Month” textbox And I select “19” in “Card End Year” textbox And I enter “123” in “Card Validation” textbox And I click the "Pay with Card (Add Card)" button Then I should be on the "Download" page
Business focused When I go to the "Checkout" And I enter a valid credit card  And pay Then I should be taken to my Downloads
Conjunction Steps Scenario: Recommendations should include other similar purchased products   Given customer order for "Trailhead Locking Carabiner" and "Climbing Rope with Single Caribiner"   And customer order for "Trailhead Locking Carabiner" and "North Star Compass" Given I have shades and a brand new Mustang
Reuse and recombine Scenario: Recommendations should include other similar purchased products   Given the following customers and orders:    |customer      | order_list |    |Customer A  | Trailhead Locking Carabiner, Climbing Rope with Single Caribiner |    |Customer B  | Trailhead Locking Carabiner, North Star Compass | Given I have shades  And I have a brand new Mustang
All steps within a single file
Steps focused around application domain
One environment file
Small, focused environment config
Multiple extension frameworks Test command line applications Test Silverlightlex Test WPF based desktop applications Execute in parallel across multiple machines
Lonestar
Outside-in Development
RSpec http://www.flickr.com/photos/dodgsun/467076780/
Context Specification
Shift focus Final Intent
Code Coverage Feature coverage is far more important
Ruby (via IronRuby) p = ProductController.new(nil) C# public class ProductController : Controller { IStoreService _service;    public ProductController(IStoreService service)    {       _service = service;    } } Thanks to TekPub for Kona sample
Define the context C# public ActionResult Index(int? id) { ProductListViewModel model = null;    if (id.HasValue)       model = _service.GetHomeModel(id.Value);    else       return RedirectToAction("Index", "Home");       return View(model); } Ruby (via IronRuby) describe ProductController, “Product homepage requested" do   context "when Category ID is empty" do   end end Thanks to TekPub for Kona sample
Create the context $: << ‘../../Kona/bin/’ require ‘Kona.dll’ Include Kona::Controllers describe ProductController, “Product homepage requested" do   context "when Category ID is empty" do   end end Thanks to TekPub for Kona sample
Create the context require '../spec_helper‘ describe ProductController, “Product homepage requested" do   context "when Category ID is empty" do   end end Thanks to TekPub for Kona sample
Create the context require '../spec_helper‘ describe ProductController, “Product homepage requested" do   context "when Category ID is empty" do      before(:each) do         controller = ProductController.new nil category_id = nil         @result = controller.Indexcategory_id      end   end end Thanks to TekPub for Kona sample
Define the spec require '../spec_helper‘ describe ProductController, “Product homepage requested" do   context “with empty Category ID" do      before(:each) do ... End     it "should redirect to main landing page" do          @result.route_values[‘controller'].should == ‘Index’ 	  @result.route_values[‘home'].should == ‘Home’     end end Thanks to TekPub for Kona sample
Stubbing via caricature context “with validCategory ID" do    Before(:each) view_model = product_list('Test Category')        service = isolate Services::IStoreService service.when_receiving(:get_home_model).with(valid_category_id).return(view_model)        controller = ProductController.new service        @result = controller.Indexvalid_category_id    end    it “returns a view model” do       @result.view_model.should_not == nil    end    it “should return name of selected category” do       @result.view_model.selected_category.name.should == 'Test Category‘    end end Thanks to TekPub for Kona sample
http://www.flickr.com/photos/buro9/298994863/ WHY RUBY?
[Subject(typeof(HomeController))]public class when_the_navigation_controller_is_asked_for_the_header :           specification_for_navigation_controller{        static ActionResult result;        Establish context = () => identity_tasks.Stub(i => i.IsSignedIn()).Return(true);        Because of = () => result = subject.Menu();        It should_ask_the_identity_tasks_if_the_user_is_signed_in = () => identity_tasks.AssertWasCalled(x => x.IsSignedIn());        It should_return_the_default_view = () => result.ShouldBeAView().And().ViewName.ShouldBeEmpty();        It should_not_use_a_master_page = () => result.ShouldBeAView().And().MasterName.ShouldBeEmpty();        It should_set_the_view_model_property_to_a_new_menu_view_model = () =>result.Model<MenuViewModel>().ShouldNotBeNull();        It should_set_the_properties_of_the_view_model_correctly = () => result.Model<MenuViewModel>().IsLoggedIn.ShouldBeTrue();    }
describe HomeController, “When the navigation controller is asked for the header” do   before(:all) do       @identity_tasks.Stub(i => i.IsSignedIn()).Return(true);       @result = subject.Menu();    end   it “should ask the identity tasks if the user is signed in” do       @identity_tasks.did_receive(:is_signed_in) .should be_successful   end   it “should return the default view” do     @result.shouldbe_view     @result.view_name.shouldbe_empty   end   it “should not use a master page” do     @result.shouldbe_view     @result.master_name.shouldbe_empty   end  it “should set the view model property to a new menu view model” do     @result.shouldbe_view    @result.model.should_notbe_nil  end  it “should set the properties of the view model correctly” do     @result.model.is_logged_in.shouldbe_true  endend
Consider your test suite containing > 500 tests Each test matters. But each problem hurts more
http://www.flickr.com/photos/leon_homan/2856628778/
Focus on finding true value Look at other communities for advice, support and inspiration
@Ben_Hall Ben@BenHall.me.uk Blog.BenHall.me.uk http://lolcatgenerator.com/lolcat/120/
Tests and Databases describe Services::StoreService do   before(:all) do session = NHibernate::create_session NHibernate::insert_category session     Services::StoreService.new session     @model = service.get_home_model 0   end   it "should return constructed object" do     @model.should_notbe_nil   end   it "should return all categories from database" do     @model.Categories.to_a.Count.should == 1   end end Thanks to TekPub for Kona sample
Share specs share_examples_for "unauthorized user" do    it 'sets an-error message' do result.view_model.error_message.should == "Sorry, you need to login to access."    end    it 'redirects to the login page' do result.view_name.should   end end describe CheckoutController do it_should_behave_like “unauthorized user“describe AccountController doit_should_behave_like “unauthorized user“
Dynamically create specs def find_products(category)Product.Find(:all, :conditions=> “category #{category}”)enddescribe ‘products should be able to be added to basket' do    before(:all) do     @basket = Basket.new  endfind_products(‘Boots’).each do |p|    it “can add #{p.product_name} to basket" do      @basket.add_item p.id      @basket.should contain(p)     end  endend
INTEGRATION TESTS http://www.flickr.com/photos/gagilas/2659695352/
Useful Links http://www.github.com/BenHall http://blog.benhall.me.uk http://www.codebetter.com/blogs/benhall http://stevehodgkiss.com/2009/11/14/using-activerecord-migrator-standalone-with-sqlite-and-sqlserver-on-windows.html http://www.testingaspnet.com http://msdn.microsoft.com/en-us/magazine/dd434651.aspx http://msdn.microsoft.com/en-us/magazine/dd453038.aspx http://www.cukes.info http://github.com/aslakhellesoy/cucumber http://github.com/brynary/webrat
using Cuke4Nuke.Framework; usingNUnit.Framework; usingWatiN.Core; namespaceGoogle.StepDefinitions {     publicclassSearchSteps     {         Browser _browser;          [Before]         publicvoidSetUp()         {             _browser = new WatiN.Core.IE();         }         [After]         publicvoidTearDown()         {             if (_browser != null)             {                 _browser.Dispose();             }         }         [When(@"^(?:I'm on|I go to) the search page$")]         publicvoidGoToSearchPage()         {             _browser.GoTo("http://www.google.com/");         }         [When("^I search for quot;(.*)quot;$")]         publicvoidSearchFor(string query)         {             _browser.TextField(Find.ByName("q")).TypeText(query);             _browser.Button(Find.ByName("btnG")).Click();         }         [Then("^I should be on the search page$")]         publicvoidIsOnSearchPage()         {             Assert.That(_browser.Title == "Google");         }         [Then("^I should see quot;(.*)quot; in the results$")]         publicvoidResultsContain(stringexpectedResult)         {             Assert.That(_browser.ContainsText(expectedResult));         }     } }
Given /^(?:I'm on|I go to) the search page$/ do   visit 'http://www.google.com' end   When /^I search for "([^quot;]*)"$/ do|query|   fill_in 'q', :with => query   click_button 'Google Search' end   Then /^I should be on the search page$/ do  dom.search('title').should == "Google" end   Then /^I should see quot;(.*)quot; in the results$/ do|text|   response.should contain(text) end
Software Recommended: IronRuby Ruby Cucumber Rspec WebRat mechanize Selenium RC selenium-client Caricature activerecord-sqlserver-adapter Optional: XSP Mono JetBrain’sRubyMine JRuby Capybara Celerity Active record  active-record-model-generator Faker Guid
SQL Server and Ruby gem install activerecord-sqlserver-adapter Download dbi-0.2.2.zip  Extract dbdDO.rb to rubyite_ruby.8BDDO.rb

Contenu connexe

Similaire à Testing ASP.net and C# using Ruby (NDC2010)

Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...
Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...
Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...John Ferguson Smart Limited
 
Creating a flawless user experience, end to-end, functional to visual - Slide...
Creating a flawless user experience, end to-end, functional to visual - Slide...Creating a flawless user experience, end to-end, functional to visual - Slide...
Creating a flawless user experience, end to-end, functional to visual - Slide...Applitools
 
Growing software from examples
Growing software from examplesGrowing software from examples
Growing software from examplesSeb Rose
 
Plone Interactivity
Plone InteractivityPlone Interactivity
Plone InteractivityEric Steele
 
Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...
Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...
Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...John Ferguson Smart Limited
 
Enabling agile devliery through enabling BDD in PHP projects
Enabling agile devliery through enabling BDD in PHP projectsEnabling agile devliery through enabling BDD in PHP projects
Enabling agile devliery through enabling BDD in PHP projectsKonstantin Kudryashov
 
Gherkin for test automation in agile
Gherkin for test automation in agileGherkin for test automation in agile
Gherkin for test automation in agileViresh Doshi
 
Testing C# and ASP.net using Ruby
Testing C# and ASP.net using RubyTesting C# and ASP.net using Ruby
Testing C# and ASP.net using RubyBen Hall
 
Introduce cucumber
Introduce cucumberIntroduce cucumber
Introduce cucumberBachue Zhou
 
Executable Requirements with Behaviour-Driven Development and Cucumber - Euro...
Executable Requirements with Behaviour-Driven Development and Cucumber - Euro...Executable Requirements with Behaviour-Driven Development and Cucumber - Euro...
Executable Requirements with Behaviour-Driven Development and Cucumber - Euro...Aslak Hellesøy
 
01 startoff angularjs
01 startoff angularjs01 startoff angularjs
01 startoff angularjsErhwen Kuo
 
Getting Started With Material Design
Getting Started With Material DesignGetting Started With Material Design
Getting Started With Material DesignYasin Yildirim
 
Neil Patel - What You Need to be Measuring and How to Do It
Neil Patel - What You Need to be Measuring and How to Do ItNeil Patel - What You Need to be Measuring and How to Do It
Neil Patel - What You Need to be Measuring and How to Do ItCarsonified Team
 
Tony Vitabile .Net Portfolio
Tony Vitabile .Net PortfolioTony Vitabile .Net Portfolio
Tony Vitabile .Net Portfoliovitabile
 
Behat, Test Driven Framework for BDD by Jeevan Bhushetty
Behat, Test Driven Framework for BDD by Jeevan BhushettyBehat, Test Driven Framework for BDD by Jeevan Bhushetty
Behat, Test Driven Framework for BDD by Jeevan BhushettyAgile Testing Alliance
 
iOS Automation: XCUITest + Gherkin
iOS Automation: XCUITest + GherkiniOS Automation: XCUITest + Gherkin
iOS Automation: XCUITest + GherkinKenneth Poon
 
How To: Use Google Search Ap Is On Your Blog
How To: Use Google Search Ap Is On Your BlogHow To: Use Google Search Ap Is On Your Blog
How To: Use Google Search Ap Is On Your Blogmutex07
 
Visualforce css developer guide(by forcetree.com)
Visualforce css developer guide(by forcetree.com)Visualforce css developer guide(by forcetree.com)
Visualforce css developer guide(by forcetree.com)Edwin Vijay R
 

Similaire à Testing ASP.net and C# using Ruby (NDC2010) (20)

BDD with cucumber
BDD with cucumberBDD with cucumber
BDD with cucumber
 
Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...
Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...
Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...
 
Creating a flawless user experience, end to-end, functional to visual - Slide...
Creating a flawless user experience, end to-end, functional to visual - Slide...Creating a flawless user experience, end to-end, functional to visual - Slide...
Creating a flawless user experience, end to-end, functional to visual - Slide...
 
2_cucumber
2_cucumber2_cucumber
2_cucumber
 
Growing software from examples
Growing software from examplesGrowing software from examples
Growing software from examples
 
Plone Interactivity
Plone InteractivityPlone Interactivity
Plone Interactivity
 
Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...
Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...
Beyond Given/When/Then - why diving into Cucumber is the wrong approach to ad...
 
Enabling agile devliery through enabling BDD in PHP projects
Enabling agile devliery through enabling BDD in PHP projectsEnabling agile devliery through enabling BDD in PHP projects
Enabling agile devliery through enabling BDD in PHP projects
 
Gherkin for test automation in agile
Gherkin for test automation in agileGherkin for test automation in agile
Gherkin for test automation in agile
 
Testing C# and ASP.net using Ruby
Testing C# and ASP.net using RubyTesting C# and ASP.net using Ruby
Testing C# and ASP.net using Ruby
 
Introduce cucumber
Introduce cucumberIntroduce cucumber
Introduce cucumber
 
Executable Requirements with Behaviour-Driven Development and Cucumber - Euro...
Executable Requirements with Behaviour-Driven Development and Cucumber - Euro...Executable Requirements with Behaviour-Driven Development and Cucumber - Euro...
Executable Requirements with Behaviour-Driven Development and Cucumber - Euro...
 
01 startoff angularjs
01 startoff angularjs01 startoff angularjs
01 startoff angularjs
 
Getting Started With Material Design
Getting Started With Material DesignGetting Started With Material Design
Getting Started With Material Design
 
Neil Patel - What You Need to be Measuring and How to Do It
Neil Patel - What You Need to be Measuring and How to Do ItNeil Patel - What You Need to be Measuring and How to Do It
Neil Patel - What You Need to be Measuring and How to Do It
 
Tony Vitabile .Net Portfolio
Tony Vitabile .Net PortfolioTony Vitabile .Net Portfolio
Tony Vitabile .Net Portfolio
 
Behat, Test Driven Framework for BDD by Jeevan Bhushetty
Behat, Test Driven Framework for BDD by Jeevan BhushettyBehat, Test Driven Framework for BDD by Jeevan Bhushetty
Behat, Test Driven Framework for BDD by Jeevan Bhushetty
 
iOS Automation: XCUITest + Gherkin
iOS Automation: XCUITest + GherkiniOS Automation: XCUITest + Gherkin
iOS Automation: XCUITest + Gherkin
 
How To: Use Google Search Ap Is On Your Blog
How To: Use Google Search Ap Is On Your BlogHow To: Use Google Search Ap Is On Your Blog
How To: Use Google Search Ap Is On Your Blog
 
Visualforce css developer guide(by forcetree.com)
Visualforce css developer guide(by forcetree.com)Visualforce css developer guide(by forcetree.com)
Visualforce css developer guide(by forcetree.com)
 

Plus de Ben Hall

The Art Of Documentation - NDC Porto 2022
The Art Of Documentation - NDC Porto 2022The Art Of Documentation - NDC Porto 2022
The Art Of Documentation - NDC Porto 2022Ben Hall
 
The Art Of Documentation for Open Source Projects
The Art Of Documentation for Open Source ProjectsThe Art Of Documentation for Open Source Projects
The Art Of Documentation for Open Source ProjectsBen Hall
 
Three Years of Lessons Running Potentially Malicious Code Inside Containers
Three Years of Lessons Running Potentially Malicious Code Inside ContainersThree Years of Lessons Running Potentially Malicious Code Inside Containers
Three Years of Lessons Running Potentially Malicious Code Inside ContainersBen Hall
 
Containers without docker
Containers without dockerContainers without docker
Containers without dockerBen Hall
 
Deploying windows containers with kubernetes
Deploying windows containers with kubernetesDeploying windows containers with kubernetes
Deploying windows containers with kubernetesBen Hall
 
The Art of Documentation and Readme.md for Open Source Projects
The Art of Documentation and Readme.md for Open Source ProjectsThe Art of Documentation and Readme.md for Open Source Projects
The Art of Documentation and Readme.md for Open Source ProjectsBen Hall
 
How Secure Are Docker Containers?
How Secure Are Docker Containers?How Secure Are Docker Containers?
How Secure Are Docker Containers?Ben Hall
 
The Challenges of Becoming Cloud Native
The Challenges of Becoming Cloud NativeThe Challenges of Becoming Cloud Native
The Challenges of Becoming Cloud NativeBen Hall
 
Scaling Docker Containers using Kubernetes and Azure Container Service
Scaling Docker Containers using Kubernetes and Azure Container ServiceScaling Docker Containers using Kubernetes and Azure Container Service
Scaling Docker Containers using Kubernetes and Azure Container ServiceBen Hall
 
The art of documentation and readme.md
The art of documentation and readme.mdThe art of documentation and readme.md
The art of documentation and readme.mdBen Hall
 
Experimenting and Learning Kubernetes and Tensorflow
Experimenting and Learning Kubernetes and TensorflowExperimenting and Learning Kubernetes and Tensorflow
Experimenting and Learning Kubernetes and TensorflowBen Hall
 
Running .NET on Docker
Running .NET on DockerRunning .NET on Docker
Running .NET on DockerBen Hall
 
Real World Lessons on the Pain Points of Node.JS Application
Real World Lessons on the Pain Points of Node.JS ApplicationReal World Lessons on the Pain Points of Node.JS Application
Real World Lessons on the Pain Points of Node.JS ApplicationBen Hall
 
Tips on solving E_TOO_MANY_THINGS_TO_LEARN with Kubernetes
Tips on solving E_TOO_MANY_THINGS_TO_LEARN with KubernetesTips on solving E_TOO_MANY_THINGS_TO_LEARN with Kubernetes
Tips on solving E_TOO_MANY_THINGS_TO_LEARN with KubernetesBen Hall
 
Deploying applications to Windows Server 2016 and Windows Containers
Deploying applications to Windows Server 2016 and Windows ContainersDeploying applications to Windows Server 2016 and Windows Containers
Deploying applications to Windows Server 2016 and Windows ContainersBen Hall
 
The How and Why of Windows containers
The How and Why of Windows containersThe How and Why of Windows containers
The How and Why of Windows containersBen Hall
 
Lessons from running potentially malicious code inside containers
Lessons from running potentially malicious code inside containersLessons from running potentially malicious code inside containers
Lessons from running potentially malicious code inside containersBen Hall
 
Deploying Windows Containers on Windows Server 2016
Deploying Windows Containers on Windows Server 2016Deploying Windows Containers on Windows Server 2016
Deploying Windows Containers on Windows Server 2016Ben Hall
 
Learning Patterns for the Overworked Developer
Learning Patterns for the Overworked DeveloperLearning Patterns for the Overworked Developer
Learning Patterns for the Overworked DeveloperBen Hall
 
Real World Lessons on the Pain Points of Node.js Applications
Real World Lessons on the Pain Points of Node.js ApplicationsReal World Lessons on the Pain Points of Node.js Applications
Real World Lessons on the Pain Points of Node.js ApplicationsBen Hall
 

Plus de Ben Hall (20)

The Art Of Documentation - NDC Porto 2022
The Art Of Documentation - NDC Porto 2022The Art Of Documentation - NDC Porto 2022
The Art Of Documentation - NDC Porto 2022
 
The Art Of Documentation for Open Source Projects
The Art Of Documentation for Open Source ProjectsThe Art Of Documentation for Open Source Projects
The Art Of Documentation for Open Source Projects
 
Three Years of Lessons Running Potentially Malicious Code Inside Containers
Three Years of Lessons Running Potentially Malicious Code Inside ContainersThree Years of Lessons Running Potentially Malicious Code Inside Containers
Three Years of Lessons Running Potentially Malicious Code Inside Containers
 
Containers without docker
Containers without dockerContainers without docker
Containers without docker
 
Deploying windows containers with kubernetes
Deploying windows containers with kubernetesDeploying windows containers with kubernetes
Deploying windows containers with kubernetes
 
The Art of Documentation and Readme.md for Open Source Projects
The Art of Documentation and Readme.md for Open Source ProjectsThe Art of Documentation and Readme.md for Open Source Projects
The Art of Documentation and Readme.md for Open Source Projects
 
How Secure Are Docker Containers?
How Secure Are Docker Containers?How Secure Are Docker Containers?
How Secure Are Docker Containers?
 
The Challenges of Becoming Cloud Native
The Challenges of Becoming Cloud NativeThe Challenges of Becoming Cloud Native
The Challenges of Becoming Cloud Native
 
Scaling Docker Containers using Kubernetes and Azure Container Service
Scaling Docker Containers using Kubernetes and Azure Container ServiceScaling Docker Containers using Kubernetes and Azure Container Service
Scaling Docker Containers using Kubernetes and Azure Container Service
 
The art of documentation and readme.md
The art of documentation and readme.mdThe art of documentation and readme.md
The art of documentation and readme.md
 
Experimenting and Learning Kubernetes and Tensorflow
Experimenting and Learning Kubernetes and TensorflowExperimenting and Learning Kubernetes and Tensorflow
Experimenting and Learning Kubernetes and Tensorflow
 
Running .NET on Docker
Running .NET on DockerRunning .NET on Docker
Running .NET on Docker
 
Real World Lessons on the Pain Points of Node.JS Application
Real World Lessons on the Pain Points of Node.JS ApplicationReal World Lessons on the Pain Points of Node.JS Application
Real World Lessons on the Pain Points of Node.JS Application
 
Tips on solving E_TOO_MANY_THINGS_TO_LEARN with Kubernetes
Tips on solving E_TOO_MANY_THINGS_TO_LEARN with KubernetesTips on solving E_TOO_MANY_THINGS_TO_LEARN with Kubernetes
Tips on solving E_TOO_MANY_THINGS_TO_LEARN with Kubernetes
 
Deploying applications to Windows Server 2016 and Windows Containers
Deploying applications to Windows Server 2016 and Windows ContainersDeploying applications to Windows Server 2016 and Windows Containers
Deploying applications to Windows Server 2016 and Windows Containers
 
The How and Why of Windows containers
The How and Why of Windows containersThe How and Why of Windows containers
The How and Why of Windows containers
 
Lessons from running potentially malicious code inside containers
Lessons from running potentially malicious code inside containersLessons from running potentially malicious code inside containers
Lessons from running potentially malicious code inside containers
 
Deploying Windows Containers on Windows Server 2016
Deploying Windows Containers on Windows Server 2016Deploying Windows Containers on Windows Server 2016
Deploying Windows Containers on Windows Server 2016
 
Learning Patterns for the Overworked Developer
Learning Patterns for the Overworked DeveloperLearning Patterns for the Overworked Developer
Learning Patterns for the Overworked Developer
 
Real World Lessons on the Pain Points of Node.js Applications
Real World Lessons on the Pain Points of Node.js ApplicationsReal World Lessons on the Pain Points of Node.js Applications
Real World Lessons on the Pain Points of Node.js Applications
 

Dernier

Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Scriptwesley chun
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherRemote DBA Services
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilV3cube
 
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
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?Antenna Manufacturer Coco
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
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
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsMaria Levchenko
 
🐬 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
 
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
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...DianaGray10
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdfhans926745
 
HTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesHTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesBoston Institute of Analytics
 
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
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
Tech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdfTech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdfhans926745
 
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
 

Dernier (20)

Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Strategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a FresherStrategies for Landing an Oracle DBA Job as a Fresher
Strategies for Landing an Oracle DBA Job as a Fresher
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
Developing An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of BrazilDeveloping An App To Navigate The Roads of Brazil
Developing An App To Navigate The Roads of Brazil
 
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
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?What Are The Drone Anti-jamming Systems Technology?
What Are The Drone Anti-jamming Systems Technology?
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
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
 
Handwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed textsHandwritten Text Recognition for manuscripts and early printed texts
Handwritten Text Recognition for manuscripts and early printed texts
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
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
 
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
Connector Corner: Accelerate revenue generation using UiPath API-centric busi...
 
[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf[2024]Digital Global Overview Report 2024 Meltwater.pdf
[2024]Digital Global Overview Report 2024 Meltwater.pdf
 
HTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation StrategiesHTML Injection Attacks: Impact and Mitigation Strategies
HTML Injection Attacks: Impact and Mitigation Strategies
 
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...
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
Tech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdfTech Trends Report 2024 Future Today Institute.pdf
Tech Trends Report 2024 Future Today Institute.pdf
 
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
 

Testing ASP.net and C# using Ruby (NDC2010)

  • 1. Testing C# and ASP.net using Ruby Meerkatalyst @Ben_HallBen@BenHall.me.ukBlog.BenHall.me.ukCodeBetter.com/blogs/benhall
  • 2. London based C# MVPWeb Developer @ 7digital.com Working on a number of Open Source Projects Co-Author of Testing ASP.net Web Applications http://www.testingaspnet.com
  • 3. Outside-in development UI level testing Cucumber Object level testing using RSpec
  • 7. Realised Ruby doesn’t have as many problems as .net
  • 10. Behaviour Driven Development Cucumber, RSpec and many others
  • 12. Focus
  • 13.
  • 14. UI Testing is not hard... Unless you make an effort
  • 15.
  • 16. What does this do? [Test]public void WatiNSearchText_SearchWatiN_TextDisplayedOnScreen(){    IE ie = new IE("http://localhost:49992/WatiNSite/");    ie.TextField(Find.ByName(“q")).TypeText("WatiN");    ie.Button(Find.ByValue("Search")).Click();    bool result = ie.Text.Contains("WatiN");    Assert.IsTrue(result); }
  • 17.
  • 19. visit click_link fill_in click_button check and uncheck choose select attach_file
  • 22. visit ‘http://www.google.com’ fill_in :q, :with => ‘asp.net’ click_button ‘Google Search’ response_body.should contain(‘Microsoft’)
  • 23. Design UI for testability Outside-in development encourages this
  • 25. Hard and Important Production data in dev anyone?
  • 26. Active Record and SQL Server Order.create
  • 27. class Order < ActiveRecord::Base set_primary_key :OrderID has_many :OrderItem has_one :OrderStatus, :primary_key => "OrderStatusID", :foreign_key => "OrderStatusID" belongs_to :Customer, :primary_key => "UserName", :foreign_key => "UserName" def self.create() order = Order.new (:modified_on => DateTime.now, :created_on => DateTime.now, :order_id => Guid.new.to_s) order.OrderStatusID = OrderStatus.find_or_create order.Customer = Customer.find_or_create(Faker::Internet.user_name) order.save! return order end end Legacy Database Looking at auto-generating model for testing
  • 28. Test Data Builders ProductCatalogBuilder .create(10.products) .for_shop(123) Customer .create(“Bob”) .owning(10.products) .with_credit_card(CreditCard.create) .with_address(Address.create)
  • 29.
  • 30. 2 rules of data generation Always insert Always clean up
  • 31. We still need to write the tests in a successful manner
  • 33. Feature:Search Google In order to find information As a researcher I want to search google    Scenario: Searching for a valid term GivenI visit "http://www.google.com/"     WhenI enter a search for "asp.net"     AndI click the "Google Search" button     ThenI should see the first result "The Official Microsoft ASP.NET Site"
  • 34. Given /^I visit "([^quot;]*)"$/ do |website|   visit website end   When /^I enter a search for "([^quot;]*)"$/ do |term|   fill_in :q, :with => term end   When /^I click the "([^quot;]*)" button$/ do |button|   click_button button end   Then /^I should see the first result "([^quot;]*)"$/ do |result|   response_body.should contain(result) end
  • 35. Thanks to TekPub for Kona sample
  • 36. Thanks to TekPub for Kona sample
  • 37. Feature: Display Products In order to browse the catalog The customer Needs to see products Scenario: Single featured product on homepage Given the featured product "Adventure Works 20x30 Binoculars" When I visit the homepage Then I should see "Adventure Works 20x30 Binoculars" listed under "Featured"
  • 38. Given /^the featured product "([^quot;]*)"$/ do |product_name| Product.createproduct_name, ‘featured’ end
  • 39. When /^I visit the homepage$/ do visit url + '/' end
  • 40. “Designed” UI for Testability Then /^I should see "([^quot;]*)" listed under "([^quot;]*)"$/ do |product, area| within div_id(area) do |products| products.should contain(product) end End def div_id(area) "#" + area.downcase.underscore end
  • 41. Using a ‘real’ framework Unit testing frameworks for UI testing? Really?!
  • 42. Before do open_connection empty_database end at_exit do empty_database End def empty_database date_of_last_restore = '01/01/2010' OrderItem.delete_all["DateAdded > ?", date_of_last_restore] Order.delete_all["CreatedOn > ?", date_of_last_restore] end Multiple Hooks
  • 43. require 'cucumber_screenshot' After do |scenario| screenshot if scenario.failed? end AfterStep('@screenshot') do |scenario| screenshot if screenshot_due? end
  • 44. def url "http://www.website.local" end Webrat.configure do |config| config.mode = :selenium config.application_framework = :external end env_selenium.rb
  • 45. Webrat.configure do |config| config.mode = :selenium config.application_framework = :external config.selenium_browser_key = get_browser_key end def get_browser_key() command = "*firefox" command = ENV['BROWSER'] if ENV['BROWSER'] return command end env_selenium.rb
  • 46. cucumber --profile selenium browser=*firefox cucumber --profile selenium browser=*safari cucumber --profile selenium browser=*iexplore cucumber --profile selenium browser=*googlechrome
  • 47. env_headless.rb Webrat.configure do |config|   config.mode = :mechanize end cucumber --profile webrat
  • 49. Noisy, repeated scenarios Scenario: Blowout Specials Given "Cascade Fur-lined Hiking Boots" in "Blowout Specials" When I visit the homepage Then I should see "Cascade Fur-lined Hiking Boots" listed under "Blowout Specials“ Scenario: Blowout Specials Given " Trailhead Locking Carabiner " in "Blowout Specials" When I visit the homepage Then I should see "Trailhead Locking Carabiner " listed under "Blowout Specials" Scenario: Blowout Specials Given " Climbing Rope with Single Caribiner " in "Blowout Specials" When I visit the homepage Then I should see " Climbing Rope with Single Caribiner " listed under "Blowout Specials"
  • 50. Single scenario, multiple examples Scenario Outline: Blowout Specials Given <product> in "Blowout Specials" When I visit the homepage Then I should see <product> listed under "Blowout Specials" Examples: | product | | "Cascade Fur-lined Hiking Boots" | | "Trailhead Locking Carabiner" | | "Climbing Rope with Single Caribiner" |
  • 51. Long scenarios When I go to the "Checkout" page And I enter “Mr A. Nonymous ” in “Card Name” textbox And I enter “1111111111111111” in “Card Number” textbox And I enter “GU1 2PE” in “Card Post Code” textbox And I select “01” in “Card Start Month” textbox And I select “09” in “Card Start Year” textbox And I select “01” in “Card End Month” textbox And I select “19” in “Card End Year” textbox And I enter “123” in “Card Validation” textbox And I click the "Pay with Card (Add Card)" button Then I should be on the "Download" page
  • 52. When I go to the "Checkout" page And I enter a new credit card: | type       | field     | value             | | textbox   | Card Name         | Mr A. Nonymous   | | textbox   | Card Number       | 4444333322221111 | | textbox   | Card Post Code   | GU1 2PE           | | select     | Card Start Month | 01               | | select   | Card Start Year  | 09               | | select     | Card End Month   | 01               | | select   | Card End Year    | 19               | | textbox   | Card Validation  | 123              | And I click the "Pay with Card (Add Card)" button Then I should be on the "Download" page
  • 53. Clear, re-useable, readable When I go to the "Checkout" page And I enter a valid credit card And I click the "Pay with Card (Add Card)" button Then I should be on the "Download" page
  • 54. Implementation details in steps When I go to the "Checkout" page And I enter “Mr A. Nonymous ” in “Card Name” textbox And I enter “1111111111111111” in “Card Number” textbox And I enter “GU1 2PE” in “Card Post Code” textbox And I select “01” in “Card Start Month” textbox And I select “09” in “Card Start Year” textbox And I select “01” in “Card End Month” textbox And I select “19” in “Card End Year” textbox And I enter “123” in “Card Validation” textbox And I click the "Pay with Card (Add Card)" button Then I should be on the "Download" page
  • 55. Business focused When I go to the "Checkout" And I enter a valid credit card And pay Then I should be taken to my Downloads
  • 56. Conjunction Steps Scenario: Recommendations should include other similar purchased products Given customer order for "Trailhead Locking Carabiner" and "Climbing Rope with Single Caribiner" And customer order for "Trailhead Locking Carabiner" and "North Star Compass" Given I have shades and a brand new Mustang
  • 57. Reuse and recombine Scenario: Recommendations should include other similar purchased products Given the following customers and orders: |customer | order_list | |Customer A | Trailhead Locking Carabiner, Climbing Rope with Single Caribiner | |Customer B | Trailhead Locking Carabiner, North Star Compass | Given I have shades And I have a brand new Mustang
  • 58. All steps within a single file
  • 59. Steps focused around application domain
  • 62. Multiple extension frameworks Test command line applications Test Silverlightlex Test WPF based desktop applications Execute in parallel across multiple machines
  • 68. Code Coverage Feature coverage is far more important
  • 69.
  • 70. Ruby (via IronRuby) p = ProductController.new(nil) C# public class ProductController : Controller { IStoreService _service; public ProductController(IStoreService service) { _service = service; } } Thanks to TekPub for Kona sample
  • 71. Define the context C# public ActionResult Index(int? id) { ProductListViewModel model = null; if (id.HasValue) model = _service.GetHomeModel(id.Value); else return RedirectToAction("Index", "Home"); return View(model); } Ruby (via IronRuby) describe ProductController, “Product homepage requested" do context "when Category ID is empty" do end end Thanks to TekPub for Kona sample
  • 72. Create the context $: << ‘../../Kona/bin/’ require ‘Kona.dll’ Include Kona::Controllers describe ProductController, “Product homepage requested" do context "when Category ID is empty" do end end Thanks to TekPub for Kona sample
  • 73. Create the context require '../spec_helper‘ describe ProductController, “Product homepage requested" do context "when Category ID is empty" do end end Thanks to TekPub for Kona sample
  • 74. Create the context require '../spec_helper‘ describe ProductController, “Product homepage requested" do context "when Category ID is empty" do before(:each) do controller = ProductController.new nil category_id = nil @result = controller.Indexcategory_id end end end Thanks to TekPub for Kona sample
  • 75. Define the spec require '../spec_helper‘ describe ProductController, “Product homepage requested" do context “with empty Category ID" do before(:each) do ... End it "should redirect to main landing page" do @result.route_values[‘controller'].should == ‘Index’ @result.route_values[‘home'].should == ‘Home’ end end Thanks to TekPub for Kona sample
  • 76. Stubbing via caricature context “with validCategory ID" do Before(:each) view_model = product_list('Test Category') service = isolate Services::IStoreService service.when_receiving(:get_home_model).with(valid_category_id).return(view_model) controller = ProductController.new service @result = controller.Indexvalid_category_id end it “returns a view model” do @result.view_model.should_not == nil end it “should return name of selected category” do @result.view_model.selected_category.name.should == 'Test Category‘ end end Thanks to TekPub for Kona sample
  • 78. [Subject(typeof(HomeController))]public class when_the_navigation_controller_is_asked_for_the_header : specification_for_navigation_controller{ static ActionResult result; Establish context = () => identity_tasks.Stub(i => i.IsSignedIn()).Return(true); Because of = () => result = subject.Menu(); It should_ask_the_identity_tasks_if_the_user_is_signed_in = () => identity_tasks.AssertWasCalled(x => x.IsSignedIn()); It should_return_the_default_view = () => result.ShouldBeAView().And().ViewName.ShouldBeEmpty(); It should_not_use_a_master_page = () => result.ShouldBeAView().And().MasterName.ShouldBeEmpty(); It should_set_the_view_model_property_to_a_new_menu_view_model = () =>result.Model<MenuViewModel>().ShouldNotBeNull(); It should_set_the_properties_of_the_view_model_correctly = () => result.Model<MenuViewModel>().IsLoggedIn.ShouldBeTrue(); }
  • 79. describe HomeController, “When the navigation controller is asked for the header” do before(:all) do @identity_tasks.Stub(i => i.IsSignedIn()).Return(true); @result = subject.Menu(); end it “should ask the identity tasks if the user is signed in” do @identity_tasks.did_receive(:is_signed_in) .should be_successful end it “should return the default view” do @result.shouldbe_view @result.view_name.shouldbe_empty end it “should not use a master page” do @result.shouldbe_view @result.master_name.shouldbe_empty end it “should set the view model property to a new menu view model” do @result.shouldbe_view @result.model.should_notbe_nil end it “should set the properties of the view model correctly” do @result.model.is_logged_in.shouldbe_true endend
  • 80. Consider your test suite containing > 500 tests Each test matters. But each problem hurts more
  • 82. Focus on finding true value Look at other communities for advice, support and inspiration
  • 83. @Ben_Hall Ben@BenHall.me.uk Blog.BenHall.me.uk http://lolcatgenerator.com/lolcat/120/
  • 84. Tests and Databases describe Services::StoreService do before(:all) do session = NHibernate::create_session NHibernate::insert_category session Services::StoreService.new session @model = service.get_home_model 0 end it "should return constructed object" do @model.should_notbe_nil end it "should return all categories from database" do @model.Categories.to_a.Count.should == 1 end end Thanks to TekPub for Kona sample
  • 85. Share specs share_examples_for "unauthorized user" do it 'sets an-error message' do result.view_model.error_message.should == "Sorry, you need to login to access." end it 'redirects to the login page' do result.view_name.should end end describe CheckoutController do it_should_behave_like “unauthorized user“describe AccountController doit_should_behave_like “unauthorized user“
  • 86. Dynamically create specs def find_products(category)Product.Find(:all, :conditions=> “category #{category}”)enddescribe ‘products should be able to be added to basket' do before(:all) do @basket = Basket.new endfind_products(‘Boots’).each do |p| it “can add #{p.product_name} to basket" do @basket.add_item p.id @basket.should contain(p) end endend
  • 88. Useful Links http://www.github.com/BenHall http://blog.benhall.me.uk http://www.codebetter.com/blogs/benhall http://stevehodgkiss.com/2009/11/14/using-activerecord-migrator-standalone-with-sqlite-and-sqlserver-on-windows.html http://www.testingaspnet.com http://msdn.microsoft.com/en-us/magazine/dd434651.aspx http://msdn.microsoft.com/en-us/magazine/dd453038.aspx http://www.cukes.info http://github.com/aslakhellesoy/cucumber http://github.com/brynary/webrat
  • 89. using Cuke4Nuke.Framework; usingNUnit.Framework; usingWatiN.Core; namespaceGoogle.StepDefinitions {     publicclassSearchSteps     {         Browser _browser; [Before]         publicvoidSetUp()         {             _browser = new WatiN.Core.IE();         } [After]         publicvoidTearDown()         {             if (_browser != null)             {                 _browser.Dispose();             }         } [When(@"^(?:I'm on|I go to) the search page$")]         publicvoidGoToSearchPage()         {             _browser.GoTo("http://www.google.com/");         } [When("^I search for quot;(.*)quot;$")]         publicvoidSearchFor(string query)         {             _browser.TextField(Find.ByName("q")).TypeText(query);             _browser.Button(Find.ByName("btnG")).Click();         } [Then("^I should be on the search page$")]         publicvoidIsOnSearchPage()         {             Assert.That(_browser.Title == "Google");         } [Then("^I should see quot;(.*)quot; in the results$")]         publicvoidResultsContain(stringexpectedResult)         {             Assert.That(_browser.ContainsText(expectedResult));         }     } }
  • 90. Given /^(?:I'm on|I go to) the search page$/ do   visit 'http://www.google.com' end   When /^I search for "([^quot;]*)"$/ do|query|   fill_in 'q', :with => query   click_button 'Google Search' end   Then /^I should be on the search page$/ do  dom.search('title').should == "Google" end   Then /^I should see quot;(.*)quot; in the results$/ do|text|   response.should contain(text) end
  • 91. Software Recommended: IronRuby Ruby Cucumber Rspec WebRat mechanize Selenium RC selenium-client Caricature activerecord-sqlserver-adapter Optional: XSP Mono JetBrain’sRubyMine JRuby Capybara Celerity Active record active-record-model-generator Faker Guid
  • 92. SQL Server and Ruby gem install activerecord-sqlserver-adapter Download dbi-0.2.2.zip Extract dbdDO.rb to rubyite_ruby.8BDDO.rb

Notes de l'éditeur

  1. Both to the customer and to the teamCost of defects to 0Every test needs to justify itselfBut not just justify, add value both during the initial development and going forward. After working on a number of large scale .net based automation projects I started to question how much value I was adding to the project. This lead me to look at other communities as inspiration
  2. More abstracted away... As such nicer for testingMore fluid, more human readable.Perfect for tests. This is why I looked at how I can start using Ruby both in practice and mindset
  3. System brings together different parts to solve a particular problem
  4. get_div_id == “Design UI for Testability”
  5. get_div_id == “Design UI for Testability”
  6. get_div_id == “Design UI for Testability”
  7. get_div_id == “Design UI for Testability”
  8. get_div_id == “Design UI for Testability”
  9. get_div_id == “Design UI for Testability”
  10. get_div_id == “Design UI for Testability”
  11. get_div_id == “Design UI for Testability”
  12. get_div_id == “Design UI for Testability”
  13. get_div_id == “Design UI for Testability”
  14. get_div_id == “Design UI for Testability”
  15. Often forgot in the .Net world...Started to come more maintain stream thanks to Aaron Jenson and Scott BellwareBounded contexts
  16. Behaviour can be isolated units like TDDBut also accept that it might involve a number of other classes Defining the behaviour of our system, means we aren’t too focused on
  17. Feature Coverage
  18. http://whocanhelpme.codeplex.com/Good example of how to use Mspec with MVC. Sadly, I think Rspec has a nicer syntax.Naming + tests are very good.