Testing ASP.net using Ruby<br />Meerkatalyst<br />@Ben_HallBen@BenHall.me.ukBlog.BenHall.me.uk<br />
1|	Why you should care2|	Object Level testing3|	UI level testing<br />
What do I mean by Testing ASP.net?<br />
Co-Author of <br />Testing ASP.net Web Applications<br />http://www.testingaspnet.com<br />
WHY TEST?<br />http://www.flickr.com/photos/atomicpuppy/2132073976/<br />
It is 2010. Automated testing is no longer controversial.<br />
http://nerddinner.codeplex.com/SourceControl/changeset/view/23425#439968<br />[TestMethod]public void EditAction_Retrieves...
http://nerddinner.codeplex.com/SourceControl/changeset/view/23425#439968<br />[TestMethod]public void EditAction_Retrieves...
        [Fact]        public void RsdReturnsValidRsdDoc()        {FakeAreaServiceareaService = new FakeAreaService();areaS...
        [Fact]        public void RsdReturnsValidRsdDoc()        {FakeAreaServiceareaService = new FakeAreaService();areaS...
http://grabbagoft.blogspot.com/2007/09/authoring-stories-with-nbehave-03.html<br />[Story] public void Should_find_custome...
RECORD AND PLAYBACK<br />http://www.flickr.com/photos/gagilas/2659695352/<br />
You can make C# readable<br />But it’s hard<br />
http://www.flickr.com/photos/buro9/298994863/<br />RUBY?<br />
Natural Language<br />
http://www.flickr.com/photos/mag3737/1914076277/<br />
RSpec<br />http://www.flickr.com/photos/dodgsun/467076780/<br />
Behaviour Driven Development<br />
Intent<br />
[TestMethod]public void EditAction_Retrieves_Dinner_1_From_Repo_And_Countries_And_Sets_DinnerViewModel() {            // A...
describe<br />
describe “when editing”do<br />
describe “when editing” do<br />   it<br />end<br />
describe “when editing” do<br />it “should return countries where dinners can be hosted”<br />end<br />
D:SourceControl
erddinner-23425specs&gt;ispecDinnersController_specs.rb<br />*<br />Pending:<br />when editing should retu...
describeNerdDinner::Controllers::DinnersController, “when editing”do<br />
require  ‘NerdDinner.dll’<br />describe NerdDinner::Controllers::DinnersController, “when editing” do<br />
$: &lt;&lt; ‘../NerdDinner/bin’<br />require  ‘NerdDinner.dll’<br />describe NerdDinner::Controllers::DinnersController, “...
$: &lt;&lt; ‘../NerdDinner/bin’<br />require  ‘NerdDinner.dll’<br />Include NerdDinner::Controllers<br />describe DinnersC...
it “returns countries where dinners can be hosted” do  <br />  controller = DinnersController.new<br />end<br />
it “returns countries where dinners can be hosted” do  <br />  controller = DinnersController.new(dinner_repos(dinners))<b...
it “returns countries where dinners can be hosted” do  <br />controller = DinnersController.new(dinner_repos(dinners))<br ...
it “returns countries where dinners can be hosted” do  <br />  controller = DinnersController.new(dinner_repos(dinners))<b...
D:SourceControl
erddinner-23425specs&gt;ispecDinnersController_specs.rb<br />F<br />1)<br />&apos;NerdDinner::Controllers:...
D:SourceControl
erddinner-23425specs&gt;ispecDinnersController_specs.rb<br />.<br />Finished in 0.4355469 seconds<br />1 e...
require ‘caricature’<br />def dinner_repos(test_data)<br />IDinnerRepository.isolate(:FindUpcomingDinners) {returns test_d...
def create_dinners(count=13)<br />   dinners = []<br />count.timesdo |i|<br />      dinners &lt;&lt; Dinner.new(:country =...
describe DinnersController, &quot;when editing&quot; do  <br />  let(:dinners) {create_dinners} <br />  let(:controller) {...
result.Countries.Count().should == dinners.length<br />result.Countries.shouldhave_same_count(dinners)<br />module Matcher...
describe DinnersController, “Managing dinner reservations” do<br />  let(:dinners) { valid_dinners }<br />  let(:controlle...
describe &quot;NHibernate&quot; do<br />  before do<br />config = Configuration.new<br />    @cfg = config.configure(File....
Outside-in Development<br />
Cucumber<br />http://www.flickr.com/photos/vizzzual-dot-com/2738586453/<br />
Documentation, automated tests and development-aid<br />
[Story] public void Should_find_customers_by_name_when_name_matches() { 	Story story = new Story(&quot;List customers by n...
Feature: List customers by name  As a customer support staff  I want to search for customers in a very flexible manner  So...
Feature: List customers by nameAs a customer support staffI want to search for customers in a very flexible mannerSo that ...
D:SourceControl
erddinner-23425features&gt;cucumber list.feature<br />Feature: List customers by name<br />  As a customer...
NOT BEST PRACTICE!!<br />Given /^a set of valid customers$/ do     @repo = CreateDummyRepo()endWhen /^I ask for an existin...
Given /^customer “([^&quot;]*)” $/ do |name|    @repo = CustomerRepository.new(Customer.new(:name =&gt; name)endWhen /^I s...
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 />
EXAMPLES<br />Cucumber, WebRat and Automated UI testing<br />
One more thing...<br />
Meerkatalyst<br />
http://blog.benhall.me.uk/2009/12/sneak-peek-at-meerkatalystlonestar.html<br />
http://www.flickr.com/photos/leon_homan/2856628778/<br />
Expressing intent<br />
Ruby -&gt; C#<br />
http://www.flickr.com/photos/philliecasablanca/2456840986/<br />@Ben_HallBen@BenHall.me.ukBlog.BenHall.me.uk<br />
using Cuke4Nuke.Framework;<br />usingNUnit.Framework;<br />usingWatiN.Core;<br />namespaceGoogle.StepDefinitions<br />{<br...
Given /^(?:I&apos;m on|I go to) the search page$/ do<br />  visit &apos;http://www.google.com&apos;<br />end<br /> <br />W...
Software<br />Recommended:<br />IronRuby<br />Ruby<br />Cucumber<br />Rspec<br />WebRat<br />mechanize<br />Selenium RC<br...
Useful Links<br />http://www.github.com/BenHall<br />http://blog.benhall.me.uk<br />http://stevehodgkiss.com/2009/11/14/us...
Getting SQL Server to work<br />gem install activerecord-sqlserver-adapter<br />Download dbi-0.2.2.zip <br />Extract dbdAD...
Upcoming SlideShare
Loading in...5
×

Testing ASP.net Web Applications using Ruby

1,655

Published on

Presentation of Testing ASP.net using Ruby I gave at DDD8, January 30th 2010.

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

No Downloads
Views
Total Views
1,655
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
32
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Testing ASP.net Web Applications using Ruby

  1. 1. Testing ASP.net using Ruby<br />Meerkatalyst<br />@Ben_HallBen@BenHall.me.ukBlog.BenHall.me.uk<br />
  2. 2. 1| Why you should care2| Object Level testing3| UI level testing<br />
  3. 3. What do I mean by Testing ASP.net?<br />
  4. 4. Co-Author of <br />Testing ASP.net Web Applications<br />http://www.testingaspnet.com<br />
  5. 5. WHY TEST?<br />http://www.flickr.com/photos/atomicpuppy/2132073976/<br />
  6. 6. It is 2010. Automated testing is no longer controversial.<br />
  7. 7. http://nerddinner.codeplex.com/SourceControl/changeset/view/23425#439968<br />[TestMethod]public void EditAction_Retrieves_Dinner_1_From_Repo_And_Countries_And_Sets_DinnerViewModel() { // Arrangevar controller = CreateDinnersControllerAs(&quot;someuser&quot;); // ActViewResult result = controller.Edit(1) as ViewResult; // AssertDinnerFormViewModel model = result.ViewData.Model as DinnerFormViewModel;Assert.AreEqual(13, model.Countries.Count());}<br />
  8. 8. http://nerddinner.codeplex.com/SourceControl/changeset/view/23425#439968<br />[TestMethod]public void EditAction_Retrieves_Dinner_1_From_Repo_And_Countries_And_Sets_DinnerViewModel() { // Arrangevar controller = CreateDinnersControllerAs(&quot;someuser&quot;); // ActViewResultresult = controller.Edit(1) as ViewResult; // AssertDinnerFormViewModel model = result.ViewData.Model as DinnerFormViewModel;Assert.AreEqual(13, model.Countries.Count());}<br />
  9. 9. [Fact] public void RsdReturnsValidRsdDoc() {FakeAreaServiceareaService = new FakeAreaService();areaService.StoredAreas.Add(&quot;test&quot;, new Oxite.Models.Area(false, DateTime.MinValue, null, null, Guid.NewGuid(), DateTime.MinValue, &quot;test&quot;));RouteCollection routes = new RouteCollection();routes.Add(&quot;Posts&quot;, new Route(&quot;&quot;, new MvcRouteHandler()));UrlHelper helper = new UrlHelper(new RequestContext(new FakeHttpContext(new Uri(&quot;http://oxite.net/&quot;),&quot;~/&quot;), new RouteData()), routes); Site site = new Site() { Host = new Uri(&quot;http://oxite.net&quot;) };AreaController controller = new AreaController(site, areaService, null, null, null, null, null) { Url = helper };ContentResult result = controller.Rsd(&quot;test&quot;);Assert.NotNull(result);XDocumentrsdDoc = XDocument.Parse(result.Content);XNamespacersdNamespace = &quot;http://archipelago.phrasewise.com/rsd&quot;;XElementrootElement = rsdDoc.Element(rsdNamespace + &quot;rsd&quot;);Assert.NotNull(rootElement);Assert.NotNull(rootElement.Attribute(&quot;version&quot;));Assert.Equal(&quot;1.0&quot;, rootElement.Attribute(&quot;version&quot;).Value);Assert.Equal(&quot;Oxite&quot;, rootElement.Descendants(rsdNamespace + &quot;engineName&quot;).SingleOrDefault().Value);Assert.Equal(&quot;http://oxite.net&quot;, rootElement.Descendants(rsdNamespace + &quot;engineLink&quot;).SingleOrDefault().Value);Assert.Equal(&quot;http://oxite.net/&quot;, rootElement.Descendants(rsdNamespace + &quot;homePageLink&quot;).SingleOrDefault().Value);XElementapisElement = rootElement.Descendants(rsdNamespace + &quot;apis&quot;).SingleOrDefault();Assert.NotNull(apisElement);Assert.Equal(1, apisElement.Elements().Count());XElementapiElement = apisElement.Elements().SingleOrDefault();Assert.NotNull(apiElement);Assert.Equal(rsdNamespace + &quot;api&quot;, apiElement.Name);Assert.Equal(&quot;MetaWeblog&quot;, apiElement.Attribute(&quot;name&quot;).Value);Assert.Equal(areaService.StoredAreas[&quot;test&quot;].ID.ToString(&quot;N&quot;), apiElement.Attribute(&quot;blogID&quot;).Value);Assert.Equal(&quot;true&quot;, apiElement.Attribute(&quot;preferred&quot;).Value);Assert.Equal(&quot;http://oxite.net/MetaWeblog.svc&quot;, apiElement.Attribute(&quot;apiLink&quot;).Value); }<br />http://oxite.codeplex.com/SourceControl/changeset/view/54721#419183<br />
  10. 10. [Fact] public void RsdReturnsValidRsdDoc() {FakeAreaServiceareaService = new FakeAreaService();areaService.StoredAreas.Add(&quot;test&quot;, new Oxite.Models.Area(false, DateTime.MinValue, null, null, Guid.NewGuid(), DateTime.MinValue, &quot;test&quot;));RouteCollection routes = new RouteCollection();routes.Add(&quot;Posts&quot;, new Route(&quot;&quot;, new MvcRouteHandler()));UrlHelper helper = new UrlHelper(new RequestContext(new FakeHttpContext(new Uri(&quot;http://oxite.net/&quot;),&quot;~/&quot;), new RouteData()), routes); Site site = new Site() { Host = new Uri(&quot;http://oxite.net&quot;) };AreaController controller = new AreaController(site, areaService, null, null, null, null, null) { Url = helper };ContentResult result = controller.Rsd(&quot;test&quot;);Assert.NotNull(result);XDocumentrsdDoc = XDocument.Parse(result.Content);XNamespacersdNamespace = &quot;http://archipelago.phrasewise.com/rsd&quot;;XElementrootElement = rsdDoc.Element(rsdNamespace + &quot;rsd&quot;);Assert.NotNull(rootElement);Assert.NotNull(rootElement.Attribute(&quot;version&quot;));Assert.Equal(&quot;1.0&quot;, rootElement.Attribute(&quot;version&quot;).Value);Assert.Equal(&quot;Oxite&quot;, rootElement.Descendants(rsdNamespace + &quot;engineName&quot;).SingleOrDefault().Value);Assert.Equal(&quot;http://oxite.net&quot;, rootElement.Descendants(rsdNamespace + &quot;engineLink&quot;).SingleOrDefault().Value);Assert.Equal(&quot;http://oxite.net/&quot;, rootElement.Descendants(rsdNamespace + &quot;homePageLink&quot;).SingleOrDefault().Value);XElementapisElement = rootElement.Descendants(rsdNamespace + &quot;apis&quot;).SingleOrDefault();Assert.NotNull(apisElement);Assert.Equal(1, apisElement.Elements().Count());XElementapiElement = apisElement.Elements().SingleOrDefault();Assert.NotNull(apiElement);Assert.Equal(rsdNamespace + &quot;api&quot;, apiElement.Name);Assert.Equal(&quot;MetaWeblog&quot;, apiElement.Attribute(&quot;name&quot;).Value);Assert.Equal(areaService.StoredAreas[&quot;test&quot;].ID.ToString(&quot;N&quot;), apiElement.Attribute(&quot;blogID&quot;).Value);Assert.Equal(&quot;true&quot;, apiElement.Attribute(&quot;preferred&quot;).Value);Assert.Equal(&quot;http://oxite.net/MetaWeblog.svc&quot;, apiElement.Attribute(&quot;apiLink&quot;).Value); }<br />http://oxite.codeplex.com/SourceControl/changeset/view/54721#419183<br />
  11. 11. http://grabbagoft.blogspot.com/2007/09/authoring-stories-with-nbehave-03.html<br />[Story] public void Should_find_customers_by_name_when_name_matches() { Story story = new Story(&quot;List customers by name&quot;); story.AsA(&quot;customer support staff&quot;) .IWant(&quot;to search for customers in a very flexible manner&quot;) .SoThat(&quot;I can find a customer record and provide meaningful support&quot;); CustomerRepository repo = null; Customer customer = null; story.WithScenario(&quot;Find by name&quot;) .Given(&quot;a set of valid customers&quot;, delegate { repo = CreateDummyRepo(); }) .When(&quot;I ask for an existing name&quot;, &quot;Joe Schmoe&quot;, delegate(string name) { customer = repo.FindByName(name); }) .Then(&quot;the correct customer is found and returned&quot;, delegate {Assert.That(customer.Name, Is.EqualTo(&quot;Joe Schmoe&quot;));}); }<br />
  12. 12. RECORD AND PLAYBACK<br />http://www.flickr.com/photos/gagilas/2659695352/<br />
  13. 13. You can make C# readable<br />But it’s hard<br />
  14. 14. http://www.flickr.com/photos/buro9/298994863/<br />RUBY?<br />
  15. 15. Natural Language<br />
  16. 16.
  17. 17. http://www.flickr.com/photos/mag3737/1914076277/<br />
  18. 18.
  19. 19.
  20. 20. RSpec<br />http://www.flickr.com/photos/dodgsun/467076780/<br />
  21. 21. Behaviour Driven Development<br />
  22. 22. Intent<br />
  23. 23. [TestMethod]public void EditAction_Retrieves_Dinner_1_From_Repo_And_Countries_And_Sets_DinnerViewModel() { // Arrangevar controller = CreateDinnersControllerAs(&quot;someuser&quot;); // ActViewResult result = controller.Edit(1) as ViewResult; // AssertDinnerFormViewModel model = result.ViewData.Model as DinnerFormViewModel;Assert.AreEqual(13, model.Countries.Count());}<br />
  24. 24. describe<br />
  25. 25. describe “when editing”do<br />
  26. 26. describe “when editing” do<br /> it<br />end<br />
  27. 27. describe “when editing” do<br />it “should return countries where dinners can be hosted”<br />end<br />
  28. 28. D:SourceControl erddinner-23425specs&gt;ispecDinnersController_specs.rb<br />*<br />Pending:<br />when editing should return countries where dinners can be hosted (Not Yet Implemented)<br />./DinnersController_specs.rb:2<br />Finished in 0.3511328 seconds<br />1 example, 0 failures, 1 pending<br />
  29. 29. describeNerdDinner::Controllers::DinnersController, “when editing”do<br />
  30. 30. require ‘NerdDinner.dll’<br />describe NerdDinner::Controllers::DinnersController, “when editing” do<br />
  31. 31. $: &lt;&lt; ‘../NerdDinner/bin’<br />require ‘NerdDinner.dll’<br />describe NerdDinner::Controllers::DinnersController, “when editing” do<br />
  32. 32. $: &lt;&lt; ‘../NerdDinner/bin’<br />require ‘NerdDinner.dll’<br />Include NerdDinner::Controllers<br />describe DinnersController, “when editing” do<br />
  33. 33. it “returns countries where dinners can be hosted” do <br /> controller = DinnersController.new<br />end<br />
  34. 34. it “returns countries where dinners can be hosted” do <br /> controller = DinnersController.new(dinner_repos(dinners))<br />end<br />
  35. 35. it “returns countries where dinners can be hosted” do <br />controller = DinnersController.new(dinner_repos(dinners))<br /> result = controller.Edit(1).ViewData.Model<br />end<br />
  36. 36. it “returns countries where dinners can be hosted” do <br /> controller = DinnersController.new(dinner_repos(dinners))<br /> result = controller.Edit(1).ViewData.Model<br />result.Countries.Count().should == test_data.length<br />end<br />RSpec has really powerful matchers<br />
  37. 37. D:SourceControl erddinner-23425specs&gt;ispecDinnersController_specs.rb<br />F<br />1)<br />&apos;NerdDinner::Controllers::DinnersController when editing should return countries where dinners can be hosted&apos; FAILED<br />expected: 13,<br /> got: nil (using ==)<br />./DinnersController_specs.rb:8:<br />Finished in 0.4824219 seconds<br />1 example, 1 failure<br />
  38. 38. D:SourceControl erddinner-23425specs&gt;ispecDinnersController_specs.rb<br />.<br />Finished in 0.4355469 seconds<br />1 example, 0 failures<br />
  39. 39. require ‘caricature’<br />def dinner_repos(test_data)<br />IDinnerRepository.isolate(:FindUpcomingDinners) {returns test_data} <br />End<br />
  40. 40. def create_dinners(count=13)<br /> dinners = []<br />count.timesdo |i|<br /> dinners &lt;&lt; Dinner.new(:country =&gt; “Value#{i}”)<br /> end<br />end<br />
  41. 41. describe DinnersController, &quot;when editing&quot; do <br /> let(:dinners) {create_dinners} <br /> let(:controller) {DinnersController.new(dinner_repos dinners)}<br /> it &quot;returns countries where dinners can be hosted&quot; do<br /> result = controller.Edit(dinners.first.id).view_model<br />result.Countries.Count().should == dinners.length<br /> end<br />end<br />
  42. 42. result.Countries.Count().should == dinners.length<br />result.Countries.shouldhave_same_count(dinners)<br />module Matchers <br /> class CountEqual<br /> def initialize(expected)<br /> @expected = expected<br /> end<br /> def matches?(actual)<br />actual.Count() == @expected.Count()<br /> end<br /> end<br /> def have_same_count(expected)<br />CountEqual.new(expected)<br /> end<br />end<br />Duck Typing FTW!<br />
  43. 43. describe DinnersController, “Managing dinner reservations” do<br /> let(:dinners) { valid_dinners }<br /> let(:controller) {DinnersController.new(dinner_repository dinners)}<br /> describe “when editing“it_should_behave_like “valid dinners” it &quot;returns countries where dinners can be hosted&quot; <br /> end<br /> describe “when saving“ do<br /> describe “the validation for invalid dinners” do<br /> let(:dinners) { bad_dinners(1) }it “should reject a dinner without a name”<br /> it “should reject a dinner without a email address”<br /> it “should accept a dinner if it has a name and email address”<br /> end<br /> describe “confirmation” do <br /> it “should send an email to the organiser once saved”<br /> end<br /> describe “valid dinners” do<br /> it “redirects to thank you page after completing&quot; <br /> end<br /> end<br />end<br />
  44. 44. describe &quot;NHibernate&quot; do<br /> before do<br />config = Configuration.new<br /> @cfg = config.configure(File.join(Dir.pwd, &quot;nhibernate.config&quot;))<br /> end<br /> it &quot;can create session factory&quot; do<br />session_factory = @cfg.BuildSessionFactory()<br />session_factory.should_notbe_nil<br /> end<br /> it &quot;can create session&quot; do<br />session_factory = @cfg.BuildSessionFactory()<br /> session = session_factory.open_session<br />session.should_notbe_nil<br /> end<br />end<br />
  45. 45. Outside-in Development<br />
  46. 46. Cucumber<br />http://www.flickr.com/photos/vizzzual-dot-com/2738586453/<br />
  47. 47. Documentation, automated tests and development-aid<br />
  48. 48. [Story] public void Should_find_customers_by_name_when_name_matches() { Story story = new Story(&quot;List customers by name&quot;); story.AsA(&quot;customer support staff&quot;) .IWant(&quot;to search for customers in a very flexible manner&quot;) .SoThat(&quot;I can find a customer record and provide meaningful support&quot;); CustomerRepository repo = null; Customer customer = null; story.WithScenario(&quot;Find by name&quot;) .Given(&quot;a set of valid customers&quot;, delegate { repo = CreateDummyRepo(); }) .When(&quot;I ask for an existing name&quot;, &quot;Joe Schmoe&quot;, delegate(string name) { customer = repo.FindByName(name); }) .Then(&quot;the correct customer is found and returned&quot;, delegate {Assert.That(customer.Name, Is.EqualTo(&quot;Joe Schmoe&quot;));}); }<br />
  49. 49. Feature: List customers by name As a customer support staff I want to search for customers in a very flexible manner So that I can find a customer record and provide meaningful supportScenario: Find by name Given a set of valid customers When I ask for an existing name Then the correct customer is found and returned<br />
  50. 50. Feature: List customers by nameAs a customer support staffI want to search for customers in a very flexible mannerSo that I can find a customer record and provide meaningful supportScenario: Find by name Given a set of valid customersWhen I ask for an existing nameThen the correct customer is found and returned<br />
  51. 51. D:SourceControl erddinner-23425features&gt;cucumber list.feature<br />Feature: List customers by name<br /> As a customer support staff<br /> I want to search for customers in a very flexible manner<br /> So that I can find a customer record and provide meaningful support<br /> Scenario: Find by name # list.feature:6<br /> Given a set of valid customers # list.feature:7<br /> When I ask for an existing name # list.feature:8<br /> Then the correct customer is found and returned # list.feature:9<br />1 scenario (1 undefined)<br />3 steps (3 undefined)<br />0m0.020s<br />You can implement step definitions for undefined steps with these snippets:<br />Given /^a set of valid customers$/ do<br /> pending # express the regexp above with the code you wish you had<br />end<br />When /^I ask for an existing name$/ do<br /> pending # express the regexp above with the code you wish you had<br />end<br />Then /^the correct customer is found and returned$/ do<br /> pending # express the regexp above with the code you wish you had<br />end<br />
  52. 52. NOT BEST PRACTICE!!<br />Given /^a set of valid customers$/ do @repo = CreateDummyRepo()endWhen /^I ask for an existing name$/ do @customer = @repo.FindByName(&quot;Joe Schmoe&quot;)endThen /^the correct customer is found and returned$/ do @customer.Name.should == &quot;Joe Schmoe“end<br />
  53. 53. Given /^customer “([^&quot;]*)” $/ do |name| @repo = CustomerRepository.new(Customer.new(:name =&gt; name)endWhen /^I search for customer “([^&quot;]*)”$/ do |name| @customer = @repo.FindByName(name)endThen /^”([^&quot;]*)” should be found and returned$/ do |name| @customer.Name.should == nameend<br />
  54. 54. WebRat<br />http://www.flickr.com/photos/whatwhat/22624256/<br />
  55. 55. visit<br />click_link<br />fill_in<br />click_button<br />check and uncheck<br />choose<br />select<br />attach_file<br />
  56. 56. EXAMPLES<br />Cucumber, WebRat and Automated UI testing<br />
  57. 57. One more thing...<br />
  58. 58. Meerkatalyst<br />
  59. 59. http://blog.benhall.me.uk/2009/12/sneak-peek-at-meerkatalystlonestar.html<br />
  60. 60. http://www.flickr.com/photos/leon_homan/2856628778/<br />
  61. 61. Expressing intent<br />
  62. 62. Ruby -&gt; C#<br />
  63. 63. http://www.flickr.com/photos/philliecasablanca/2456840986/<br />@Ben_HallBen@BenHall.me.ukBlog.BenHall.me.uk<br />
  64. 64. 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(@&quot;^(?:I&apos;m on|I go to) the search page$&quot;)]<br />        publicvoidGoToSearchPage()<br />        {<br />            _browser.GoTo(&quot;http://www.google.com/&quot;);<br />        }<br /> [When(&quot;^I search for &quot;(.*)&quot;$&quot;)]<br />        publicvoidSearchFor(string query)<br />        {<br />            _browser.TextField(Find.ByName(&quot;q&quot;)).TypeText(query);<br />            _browser.Button(Find.ByName(&quot;btnG&quot;)).Click();<br />        }<br /> [Then(&quot;^I should be on the search page$&quot;)]<br />        publicvoidIsOnSearchPage()<br />        {<br />            Assert.That(_browser.Title == &quot;Google&quot;);<br />        }<br /> [Then(&quot;^I should see &quot;(.*)&quot; in the results$&quot;)]<br />        publicvoidResultsContain(stringexpectedResult)<br />        {<br />            Assert.That(_browser.ContainsText(expectedResult));<br />        }<br />    }<br />}<br />
  65. 65. Given /^(?:I&apos;m on|I go to) the search page$/ do<br />  visit &apos;http://www.google.com&apos;<br />end<br /> <br />When /^I search for &quot;([^&quot;]*)&quot;$/ do|query|<br />  fill_in &apos;q&apos;, :with =&gt; query<br />  click_button &apos;Google Search&apos;<br />end<br /> <br />Then /^I should be on the search page$/ do<br /> dom.search(&apos;title&apos;).should == &quot;Google&quot;<br />end<br /> <br />Then /^I should see &quot;(.*)&quot; in the results$/ do|text|<br />  response.should contain(text)<br />end<br />
  66. 66. 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 />
  67. 67. Useful Links<br />http://www.github.com/BenHall<br />http://blog.benhall.me.uk<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://<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 />
  68. 68. Getting SQL Server to work<br />gem install activerecord-sqlserver-adapter<br />Download dbi-0.2.2.zip <br />Extract dbdADO.rb to rubysite_ruby1.8DBDADO.rb<br />
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×