Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
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

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

  • Be the first to comment

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 />

×