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
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); }
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
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
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
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
62. Multiple extension frameworks Test command line applications Test Silverlightlex Test WPF based desktop applications Execute in parallel across multiple machines
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
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
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
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
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.