Testing C# and ASP.net using Ruby<br />Meerkatalyst<br />@Ben_HallBen@BenHall.me.ukBlog.BenHall.me.ukCodeBetter.com/blogs/...
London based C# MVPWeb Developer @ 7digital.com Working on a number of Open Source Projects<br />Co-Author of <br />Testin...
Outside-in development<br />UI level testing<br />Cucumber<br />Object level testing using RSpec<br />
WHY?<br />http://www.flickr.com/photos/atomicpuppy/2132073976/<br />
VALUE<br />
State of .NET today<br />
Realised Ruby doesn’t have as many problems as .net<br />
Innovation<br />
Outside-in Development<br />
Behaviour Driven Development<br />Cucumber, RSpec and many others<br />
Direct communication with customers<br />
Focus<br />
UI Testing is not hard...<br />Unless you make an effort<br />
What does this do?<br />[Test]public void WatiNSearchText_SearchWatiN_TextDisplayedOnScreen(){    IE ie = new IE("http://l...
WebRat<br />http://www.flickr.com/photos/whatwhat/22624256/<br />
visit<br />click_link<br />fill_in<br />click_button<br />check and uncheck<br />choose<br />select<br />attach_file<br />
visit ‘http://localhost’<br />
Reduce Ceremony<br />
visit ‘http://www.google.com’<br />fill_in :q, :with => ‘asp.net’<br />click_button ‘Google Search’<br />response_body.sho...
Design UI for testability<br />Outside-in development encourages this<br />
DATA!<br />http://www.flickr.com/photos/gagilas/2659695352/<br />
Hard and Important<br />Production data in dev anyone?<br />
Active Record and SQL Server<br />Order.create<br />
class Order < ActiveRecord::Base<br />set_primary_key :OrderID<br />has_many :OrderItem<br />has_one  :OrderStatus,       ...
Test Data Builders<br />ProductCatalogBuilder<br />          .create(10.products)<br />          .for_shop(123)        <br...
Customer.find_or_create(Faker::Internet.user_name)<br />>>> Faker::Internet.user_name<br /><ul><li>"akeem_kris“</li></ul>>...
2 rules of data generation<br />Always insert<br />Always clean up<br />
We still need to write the tests in a successful manner<br />
Cucumber<br />http://www.flickr.com/photos/vizzzual-dot-com/2738586453/<br />
Feature:Search Google<br />In order to find information<br />As a researcher<br />I want to search google<br /> <br /> Sce...
Given /^I visit "([^"]*)"$/ do |website|<br />  visit website<br />end<br /> <br />When /^I enter a search for "([^"]*)"$/...
Thanks to TekPub for Kona sample<br />
Thanks to TekPub for Kona sample<br />
Feature: Display Products<br />  In order to browse the catalog<br />  The customer<br />  Needs to see products<br />Scen...
Given /^the featured product "([^"]*)"$/ do |product_name|<br />Product.createproduct_name, ‘featured’<br />end<br />
When /^I visit the homepage$/ do<br />visit url + '/'<br />end<br />
“Designed” UI for Testability<br />Then /^I should see "([^"]*)" listed under "([^"]*)"$/ do |product, area|<br />  within...
Using a ‘real’ framework<br />Unit testing frameworks for UI testing? Really?!<br />
Before do<br />open_connection<br />empty_database<br />end<br />at_exit do<br />empty_database<br />End<br />def empty_da...
require 'cucumber_screenshot'<br />After do |scenario| <br />  screenshot if scenario.failed?<br />end<br />AfterStep('@sc...
def url<br />  "http://www.website.local"<br />end<br />Webrat.configure do |config|<br />config.mode = :selenium<br />con...
Webrat.configure do |config|<br />config.mode = :selenium<br />config.application_framework = :external<br />config.seleni...
cucumber --profile selenium browser=*firefox<br />cucumber --profile selenium browser=*safari<br />cucumber --profile sele...
env_headless.rb<br />Webrat.configure do |config|<br />  config.mode = :mechanize<br />end<br />cucumber --profile webrat<...
ANTI-PATTERNS<br />http://www.flickr.com/photos/gagilas/2659695352/<br />
Noisy, repeated scenarios<br />Scenario: Blowout Specials<br />    Given "Cascade Fur-lined Hiking Boots" in "Blowout Spec...
Single scenario, multiple examples<br />Scenario Outline: Blowout Specials<br />    Given <product> in "Blowout Specials"<...
Long scenarios<br />When I go to the "Checkout" page<br />And I enter “Mr A. Nonymous ” in “Card Name” textbox<br />And I ...
When I go to the "Checkout" page<br />And I enter a new credit card:<br />       | type        | field                    ...
Clear, re-useable, readable<br />When I go to the "Checkout" page<br />And I enter a valid credit card <br />And I click t...
Implementation details in steps<br />When I go to the "Checkout" page<br />And I enter “Mr A. Nonymous ” in “Card Name” te...
Business focused<br />When I go to the "Checkout"<br />And I enter a valid credit card <br />And pay<br />Then I should be...
Conjunction Steps<br />Scenario: Recommendations should include other similar purchased products<br />  Given customer ord...
Reuse and recombine<br />Scenario: Recommendations should include other similar purchased products<br />  Given the follow...
All steps within a single file<br />
Steps focused around application domain<br />
One environment file<br />
Small, focused environment config<br />
Multiple extension frameworks<br />Test command line applications<br />Test SilverlightFlex<br />Test WPF based desktop ap...
Lonestar<br />
Outside-in Development<br />
RSpec<br />http://www.flickr.com/photos/dodgsun/467076780/<br />
Context  Specification<br />
Shift focus<br />Final Intent<br />
Code Coverage<br />Feature coverage is far more important<br />
Ruby (via IronRuby)<br />p = ProductController.new(nil)<br />C#<br />public class ProductController : Controller<br />{<br...
Define the context<br />C#<br />public ActionResult Index(int? id)<br />{<br />ProductListViewModel model = null;<br />   ...
Create the context<br />$: << ‘../../Kona/bin/’<br />require ‘Kona.dll’<br />Include Kona::Controllers<br />describe Produ...
Create the context<br />require '../spec_helper‘<br />describe ProductController, “Product homepage requested" do<br />  c...
Create the context<br />require '../spec_helper‘<br />describe ProductController, “Product homepage requested" do<br />  c...
Define the spec<br />require '../spec_helper‘<br />describe ProductController, “Product homepage requested" do<br />  cont...
Stubbing via caricature<br />context “with validCategory ID" do<br />   Before(:each)<br />view_model = product_list('Test...
http://www.flickr.com/photos/buro9/298994863/<br />WHY RUBY?<br />
[Subject(typeof(HomeController))]public class when_the_navigation_controller_is_asked_for_the_header :           specifica...
describe HomeController, “When the navigation controller is asked for the header” do   before(:all) do       @identity_tas...
Consider your test suite containing > 500 tests<br />Each test matters.<br />But each problem hurts more<br />
http://www.flickr.com/photos/leon_homan/2856628778/<br />
Focus on finding true value<br />Look at other communities for advice, support and inspiration<br />
@Ben_Hall<br />Ben@BenHall.me.uk<br />Blog.BenHall.me.uk<br />http://lolcatgenerator.com/lolcat/120/<br />
Tests and Databases<br />describe Services::StoreService do<br />  before(:all) do<br />session = NHibernate::create_sessi...
Share specs<br />share_examples_for "unauthorized user" do    it 'sets an-error message' do result.view_model.error_messag...
Dynamically create specs<br />def find_products(category)Product.Find(:all, :conditions=> “category #{category}”)enddescri...
INTEGRATION TESTS<br />http://www.flickr.com/photos/gagilas/2659695352/<br />
Useful Links<br />http://www.github.com/BenHall<br />http://blog.benhall.me.uk<br />http://www.codebetter.com/blogs/benhal...
using Cuke4Nuke.Framework;<br />usingNUnit.Framework;<br />usingWatiN.Core;<br />namespaceGoogle.StepDefinitions<br />{<br...
Given /^(?:I'm on|I go to) the search page$/ do<br />  visit 'http://www.google.com'<br />end<br /> <br />When /^I search ...
Software<br />Recommended:<br />IronRuby<br />Ruby<br />Cucumber<br />Rspec<br />WebRat<br />mechanize<br />Selenium RC<br...
SQL Server and Ruby<br />gem install activerecord-sqlserver-adapter<br />Download dbi-0.2.2.zip <br />Extract dbdADO.rb to...
Upcoming SlideShare
Loading in …5
×

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

4,415 views

Published on

Session given at NDC2010, Oslo, Norway on Testing ASP.net using Ruby

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
4,415
On SlideShare
0
From Embeds
0
Number of Embeds
5
Actions
Shares
0
Downloads
23
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide
  • 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
  • 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
  • System brings together different parts to solve a particular problem
  • get_div_id == “Design UI for Testability”
  • get_div_id == “Design UI for Testability”
  • get_div_id == “Design UI for Testability”
  • get_div_id == “Design UI for Testability”
  • get_div_id == “Design UI for Testability”
  • get_div_id == “Design UI for Testability”
  • get_div_id == “Design UI for Testability”
  • get_div_id == “Design UI for Testability”
  • get_div_id == “Design UI for Testability”
  • get_div_id == “Design UI for Testability”
  • get_div_id == “Design UI for Testability”
  • Often forgot in the .Net world...Started to come more maintain stream thanks to Aaron Jenson and Scott BellwareBounded contexts
  • 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
  • Feature Coverage
  • 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.
  • Testing ASP.net and C# using Ruby (NDC2010)

    1. 1. Testing C# and ASP.net using Ruby<br />Meerkatalyst<br />@Ben_HallBen@BenHall.me.ukBlog.BenHall.me.ukCodeBetter.com/blogs/benhall<br />
    2. 2. London based C# MVPWeb Developer @ 7digital.com Working on a number of Open Source Projects<br />Co-Author of <br />Testing ASP.net Web Applications<br />http://www.testingaspnet.com<br />
    3. 3. Outside-in development<br />UI level testing<br />Cucumber<br />Object level testing using RSpec<br />
    4. 4. WHY?<br />http://www.flickr.com/photos/atomicpuppy/2132073976/<br />
    5. 5. VALUE<br />
    6. 6. State of .NET today<br />
    7. 7. Realised Ruby doesn’t have as many problems as .net<br />
    8. 8. Innovation<br />
    9. 9. Outside-in Development<br />
    10. 10. Behaviour Driven Development<br />Cucumber, RSpec and many others<br />
    11. 11. Direct communication with customers<br />
    12. 12. Focus<br />
    13. 13.
    14. 14. UI Testing is not hard...<br />Unless you make an effort<br />
    15. 15.
    16. 16. What does this do?<br />[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); }<br />
    17. 17.
    18. 18. WebRat<br />http://www.flickr.com/photos/whatwhat/22624256/<br />
    19. 19. visit<br />click_link<br />fill_in<br />click_button<br />check and uncheck<br />choose<br />select<br />attach_file<br />
    20. 20. visit ‘http://localhost’<br />
    21. 21. Reduce Ceremony<br />
    22. 22. visit ‘http://www.google.com’<br />fill_in :q, :with => ‘asp.net’<br />click_button ‘Google Search’<br />response_body.should contain(‘Microsoft’)<br />
    23. 23. Design UI for testability<br />Outside-in development encourages this<br />
    24. 24. DATA!<br />http://www.flickr.com/photos/gagilas/2659695352/<br />
    25. 25. Hard and Important<br />Production data in dev anyone?<br />
    26. 26. Active Record and SQL Server<br />Order.create<br />
    27. 27. class Order < ActiveRecord::Base<br />set_primary_key :OrderID<br />has_many :OrderItem<br />has_one :OrderStatus, :primary_key => "OrderStatusID", :foreign_key => "OrderStatusID"<br />belongs_to :Customer, :primary_key => "UserName", :foreign_key => "UserName"<br /> def self.create()<br /> order = Order.new (:modified_on => DateTime.now, <br /> :created_on => DateTime.now, <br /> :order_id => Guid.new.to_s)<br />order.OrderStatusID = OrderStatus.find_or_create<br />order.Customer = Customer.find_or_create(Faker::Internet.user_name)<br />order.save!<br /> return order<br /> end<br />end<br />Legacy Database<br />Looking at auto-generating<br />model for testing<br />
    28. 28. Test Data Builders<br />ProductCatalogBuilder<br /> .create(10.products)<br /> .for_shop(123) <br />Customer<br /> .create(“Bob”)<br /> .owning(10.products)<br /> .with_credit_card(CreditCard.create)<br /> .with_address(Address.create) <br />
    29. 29. Customer.find_or_create(Faker::Internet.user_name)<br />>>> Faker::Internet.user_name<br /><ul><li>"akeem_kris“</li></ul>>>> Faker::Internet.user_name<br /><ul><li>"taylor.hodkiewicz“</li></ul>>>> Faker::Internet.user_name<br />=> "nicolette.nitzsche"<br />>>> Faker::Internet.email<br /><ul><li>dejon@hayeswalsh.uk</li></ul>>>> Faker::Name.name<br />=> "Murray Hermiston"<br />
    30. 30. 2 rules of data generation<br />Always insert<br />Always clean up<br />
    31. 31. We still need to write the tests in a successful manner<br />
    32. 32. Cucumber<br />http://www.flickr.com/photos/vizzzual-dot-com/2738586453/<br />
    33. 33. Feature:Search Google<br />In order to find information<br />As a researcher<br />I want to search google<br /> <br /> Scenario: Searching for a valid term<br />GivenI visit "http://www.google.com/"<br />    WhenI enter a search for "asp.net"<br />    AndI click the "Google Search" button<br />    ThenI should see the first result "The Official Microsoft ASP.NET Site"<br />
    34. 34. Given /^I visit "([^"]*)"$/ do |website|<br />  visit website<br />end<br /> <br />When /^I enter a search for "([^"]*)"$/ do |term|<br />  fill_in :q, :with => term<br />end<br /> <br />When /^I click the "([^"]*)" button$/ do |button|<br />  click_button button<br />end<br /> <br />Then /^I should see the first result "([^"]*)"$/ do |result|<br />  response_body.should contain(result)<br />end<br />
    35. 35. Thanks to TekPub for Kona sample<br />
    36. 36. Thanks to TekPub for Kona sample<br />
    37. 37. Feature: Display Products<br /> In order to browse the catalog<br /> The customer<br /> Needs to see products<br />Scenario: Single featured product on homepage<br /> Given the featured product "Adventure Works 20x30 Binoculars"<br /> When I visit the homepage<br /> Then I should see "Adventure Works 20x30 Binoculars" listed under "Featured"<br />
    38. 38. Given /^the featured product "([^"]*)"$/ do |product_name|<br />Product.createproduct_name, ‘featured’<br />end<br />
    39. 39. When /^I visit the homepage$/ do<br />visit url + '/'<br />end<br />
    40. 40. “Designed” UI for Testability<br />Then /^I should see "([^"]*)" listed under "([^"]*)"$/ do |product, area|<br /> within div_id(area) do |products|<br />products.should contain(product)<br /> end<br />End<br />def div_id(area)<br /> "#" + area.downcase.underscore<br />end<br />
    41. 41. Using a ‘real’ framework<br />Unit testing frameworks for UI testing? Really?!<br />
    42. 42. Before do<br />open_connection<br />empty_database<br />end<br />at_exit do<br />empty_database<br />End<br />def empty_database<br />date_of_last_restore = '01/01/2010'<br />OrderItem.delete_all["DateAdded > ?", date_of_last_restore]<br />Order.delete_all["CreatedOn > ?", date_of_last_restore]<br />end<br />Multiple Hooks<br />
    43. 43. require 'cucumber_screenshot'<br />After do |scenario| <br /> screenshot if scenario.failed?<br />end<br />AfterStep('@screenshot') do |scenario| <br /> screenshot if screenshot_due? <br />end<br />
    44. 44. def url<br /> "http://www.website.local"<br />end<br />Webrat.configure do |config|<br />config.mode = :selenium<br />config.application_framework = :external<br />end<br />env_selenium.rb<br />
    45. 45. Webrat.configure do |config|<br />config.mode = :selenium<br />config.application_framework = :external<br />config.selenium_browser_key = get_browser_key<br />end<br />def get_browser_key()<br /> command = "*firefox"<br /> command = ENV['BROWSER'] if ENV['BROWSER']<br /> return command<br />end<br />env_selenium.rb<br />
    46. 46. cucumber --profile selenium browser=*firefox<br />cucumber --profile selenium browser=*safari<br />cucumber --profile selenium browser=*iexplore<br />cucumber --profile selenium browser=*googlechrome<br />
    47. 47. env_headless.rb<br />Webrat.configure do |config|<br />  config.mode = :mechanize<br />end<br />cucumber --profile webrat<br />
    48. 48. ANTI-PATTERNS<br />http://www.flickr.com/photos/gagilas/2659695352/<br />
    49. 49. Noisy, repeated scenarios<br />Scenario: Blowout Specials<br /> Given "Cascade Fur-lined Hiking Boots" in "Blowout Specials"<br /> When I visit the homepage<br /> Then I should see "Cascade Fur-lined Hiking Boots" listed under "Blowout Specials“<br />Scenario: Blowout Specials<br /> Given " Trailhead Locking Carabiner " in "Blowout Specials"<br /> When I visit the homepage<br /> Then I should see "Trailhead Locking Carabiner " listed under "Blowout Specials"<br />Scenario: Blowout Specials<br /> Given " Climbing Rope with Single Caribiner " in "Blowout Specials"<br /> When I visit the homepage<br /> Then I should see " Climbing Rope with Single Caribiner " listed under "Blowout Specials"<br />
    50. 50. Single scenario, multiple examples<br />Scenario Outline: Blowout Specials<br /> Given <product> in "Blowout Specials"<br /> When I visit the homepage<br /> Then I should see <product> listed under "Blowout Specials"<br /> Examples:<br /> | product |<br /> | "Cascade Fur-lined Hiking Boots" |<br /> | "Trailhead Locking Carabiner" |<br /> | "Climbing Rope with Single Caribiner" |<br />
    51. 51. Long scenarios<br />When I go to the "Checkout" page<br />And I enter “Mr A. Nonymous ” in “Card Name” textbox<br />And I enter “1111111111111111” in “Card Number” textbox<br />And I enter “GU1 2PE” in “Card Post Code” textbox<br />And I select “01” in “Card Start Month” textbox<br />And I select “09” in “Card Start Year” textbox<br />And I select “01” in “Card End Month” textbox<br />And I select “19” in “Card End Year” textbox<br />And I enter “123” in “Card Validation” textbox<br />And I click the "Pay with Card (Add Card)" button<br />Then I should be on the "Download" page<br />
    52. 52. When I go to the "Checkout" page<br />And I enter a new credit card:<br /> | type       | field     | value             |<br /> | textbox   | Card Name         | Mr A. Nonymous   |<br /> | textbox   | Card Number       | 4444333322221111 |<br /> | textbox   | Card Post Code   | GU1 2PE           |<br /> | select     | Card Start Month | 01               |<br /> | select   | Card Start Year  | 09               |<br /> | select     | Card End Month   | 01               |<br /> | select   | Card End Year    | 19               |<br /> | textbox   | Card Validation  | 123              |<br />And I click the "Pay with Card (Add Card)" button<br />Then I should be on the "Download" page<br />
    53. 53. Clear, re-useable, readable<br />When I go to the "Checkout" page<br />And I enter a valid credit card <br />And I click the "Pay with Card (Add Card)" button<br />Then I should be on the "Download" page<br />
    54. 54. Implementation details in steps<br />When I go to the "Checkout" page<br />And I enter “Mr A. Nonymous ” in “Card Name” textbox<br />And I enter “1111111111111111” in “Card Number” textbox<br />And I enter “GU1 2PE” in “Card Post Code” textbox<br />And I select “01” in “Card Start Month” textbox<br />And I select “09” in “Card Start Year” textbox<br />And I select “01” in “Card End Month” textbox<br />And I select “19” in “Card End Year” textbox<br />And I enter “123” in “Card Validation” textbox<br />And I click the "Pay with Card (Add Card)" button<br />Then I should be on the "Download" page<br />
    55. 55. Business focused<br />When I go to the "Checkout"<br />And I enter a valid credit card <br />And pay<br />Then I should be taken to my Downloads<br />
    56. 56. Conjunction Steps<br />Scenario: Recommendations should include other similar purchased products<br /> Given customer order for "Trailhead Locking Carabiner" and "Climbing Rope with Single Caribiner"<br /> And customer order for "Trailhead Locking Carabiner" and "North Star Compass"<br />Given I have shades and a brand new Mustang<br />
    57. 57. Reuse and recombine<br />Scenario: Recommendations should include other similar purchased products<br /> Given the following customers and orders:<br /> |customer | order_list |<br /> |Customer A | Trailhead Locking Carabiner, Climbing Rope with Single Caribiner |<br /> |Customer B | Trailhead Locking Carabiner, North Star Compass |<br />Given I have shades <br />And I have a brand new Mustang<br />
    58. 58. All steps within a single file<br />
    59. 59. Steps focused around application domain<br />
    60. 60. One environment file<br />
    61. 61. Small, focused environment config<br />
    62. 62. Multiple extension frameworks<br />Test command line applications<br />Test SilverlightFlex<br />Test WPF based desktop applications<br />Execute in parallel across multiple machines<br />
    63. 63. Lonestar<br />
    64. 64. Outside-in Development<br />
    65. 65. RSpec<br />http://www.flickr.com/photos/dodgsun/467076780/<br />
    66. 66. Context Specification<br />
    67. 67. Shift focus<br />Final Intent<br />
    68. 68. Code Coverage<br />Feature coverage is far more important<br />
    69. 69.
    70. 70. Ruby (via IronRuby)<br />p = ProductController.new(nil)<br />C#<br />public class ProductController : Controller<br />{<br />IStoreService _service;<br /> public ProductController(IStoreService service)<br /> {<br /> _service = service;<br /> }<br />}<br />Thanks to TekPub for Kona sample<br />
    71. 71. Define the context<br />C#<br />public ActionResult Index(int? id)<br />{<br />ProductListViewModel model = null;<br /> if (id.HasValue)<br /> model = _service.GetHomeModel(id.Value);<br /> else<br /> return RedirectToAction("Index", "Home");<br /> return View(model);<br />}<br />Ruby (via IronRuby)<br />describe ProductController, “Product homepage requested" do<br /> context "when Category ID is empty" do<br /> end<br />end<br />Thanks to TekPub for Kona sample<br />
    72. 72. Create the context<br />$: << ‘../../Kona/bin/’<br />require ‘Kona.dll’<br />Include Kona::Controllers<br />describe ProductController, “Product homepage requested" do<br /> context "when Category ID is empty" do<br /> end<br />end<br />Thanks to TekPub for Kona sample<br />
    73. 73. Create the context<br />require '../spec_helper‘<br />describe ProductController, “Product homepage requested" do<br /> context "when Category ID is empty" do<br /> end<br />end<br />Thanks to TekPub for Kona sample<br />
    74. 74. Create the context<br />require '../spec_helper‘<br />describe ProductController, “Product homepage requested" do<br /> context "when Category ID is empty" do<br /> before(:each) do<br /> controller = ProductController.new nil<br />category_id = nil<br /> @result = controller.Indexcategory_id<br /> end<br /> end<br />end<br />Thanks to TekPub for Kona sample<br />
    75. 75. Define the spec<br />require '../spec_helper‘<br />describe ProductController, “Product homepage requested" do<br /> context “with empty Category ID" do<br /> before(:each) do ... End<br /> it "should redirect to main landing page" do<br /> @result.route_values[‘controller'].should == ‘Index’<br /> @result.route_values[‘home'].should == ‘Home’<br /> end<br />end<br />Thanks to TekPub for Kona sample<br />
    76. 76. Stubbing via caricature<br />context “with validCategory ID" do<br /> Before(:each)<br />view_model = product_list('Test Category')<br /> service = isolate Services::IStoreService<br />service.when_receiving(:get_home_model).with(valid_category_id).return(view_model)<br /> controller = ProductController.new service<br /> @result = controller.Indexvalid_category_id<br /> end<br /> it “returns a view model” do<br /> @result.view_model.should_not == nil<br /> end<br /> it “should return name of selected category” do<br /> @result.view_model.selected_category.name.should == 'Test Category‘<br /> end<br />end<br />Thanks to TekPub for Kona sample<br />
    77. 77. http://www.flickr.com/photos/buro9/298994863/<br />WHY RUBY?<br />
    78. 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(); }<br />
    79. 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<br />
    80. 80. Consider your test suite containing > 500 tests<br />Each test matters.<br />But each problem hurts more<br />
    81. 81. http://www.flickr.com/photos/leon_homan/2856628778/<br />
    82. 82. Focus on finding true value<br />Look at other communities for advice, support and inspiration<br />
    83. 83. @Ben_Hall<br />Ben@BenHall.me.uk<br />Blog.BenHall.me.uk<br />http://lolcatgenerator.com/lolcat/120/<br />
    84. 84. Tests and Databases<br />describe Services::StoreService do<br /> before(:all) do<br />session = NHibernate::create_session<br />NHibernate::insert_category session<br /> Services::StoreService.new session<br /> @model = service.get_home_model 0<br /> end<br /> it "should return constructed object" do<br /> @model.should_notbe_nil<br /> end<br /> it "should return all categories from database" do<br /> @model.Categories.to_a.Count.should == 1<br /> end<br />end<br />Thanks to TekPub for Kona sample<br />
    85. 85. Share specs<br />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“ <br />
    86. 86. Dynamically create specs<br />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<br />
    87. 87. INTEGRATION TESTS<br />http://www.flickr.com/photos/gagilas/2659695352/<br />
    88. 88. Useful Links<br />http://www.github.com/BenHall<br />http://blog.benhall.me.uk<br />http://www.codebetter.com/blogs/benhall<br />http://stevehodgkiss.com/2009/11/14/using-activerecord-migrator-standalone-with-sqlite-and-sqlserver-on-windows.html<br />http://www.testingaspnet.com<br />http://msdn.microsoft.com/en-us/magazine/dd434651.aspx<br />http://msdn.microsoft.com/en-us/magazine/dd453038.aspx<br />http://www.cukes.info<br />http://github.com/aslakhellesoy/cucumber<br />http://github.com/brynary/webrat<br />
    89. 89. using Cuke4Nuke.Framework;<br />usingNUnit.Framework;<br />usingWatiN.Core;<br />namespaceGoogle.StepDefinitions<br />{<br />    publicclassSearchSteps<br />    {<br />        Browser _browser;<br /> [Before]<br />        publicvoidSetUp()<br />        {<br />            _browser = new WatiN.Core.IE();<br />        }<br /> [After]<br />        publicvoidTearDown()<br />        {<br />            if (_browser != null)<br />            {<br />                _browser.Dispose();<br />            }<br />        }<br /> [When(@"^(?:I'm on|I go to) the search page$")]<br />        publicvoidGoToSearchPage()<br />        {<br />            _browser.GoTo("http://www.google.com/");<br />        }<br /> [When("^I search for "(.*)"$")]<br />        publicvoidSearchFor(string query)<br />        {<br />            _browser.TextField(Find.ByName("q")).TypeText(query);<br />            _browser.Button(Find.ByName("btnG")).Click();<br />        }<br /> [Then("^I should be on the search page$")]<br />        publicvoidIsOnSearchPage()<br />        {<br />            Assert.That(_browser.Title == "Google");<br />        }<br /> [Then("^I should see "(.*)" in the results$")]<br />        publicvoidResultsContain(stringexpectedResult)<br />        {<br />            Assert.That(_browser.ContainsText(expectedResult));<br />        }<br />    }<br />}<br />
    90. 90. Given /^(?:I'm on|I go to) the search page$/ do<br />  visit 'http://www.google.com'<br />end<br /> <br />When /^I search for "([^"]*)"$/ do|query|<br />  fill_in 'q', :with => query<br />  click_button 'Google Search'<br />end<br /> <br />Then /^I should be on the search page$/ do<br /> dom.search('title').should == "Google"<br />end<br /> <br />Then /^I should see "(.*)" in the results$/ do|text|<br />  response.should contain(text)<br />end<br />
    91. 91. Software<br />Recommended:<br />IronRuby<br />Ruby<br />Cucumber<br />Rspec<br />WebRat<br />mechanize<br />Selenium RC<br />selenium-client<br />Caricature<br />activerecord-sqlserver-adapter<br />Optional:<br />XSP Mono<br />JetBrain’sRubyMine<br />JRuby<br />Capybara<br />Celerity<br />Active record <br />active-record-model-generator<br />Faker<br />Guid<br />
    92. 92. SQL Server and Ruby<br />gem install activerecord-sqlserver-adapter<br />Download dbi-0.2.2.zip <br />Extract dbdADO.rb to rubysite_ruby1.8DBDADO.rb<br />

    ×