6. It is 2010. Automated testing is no longer controversial.
7. http://nerddinner.codeplex.com/SourceControl/changeset/view/23425#439968 [TestMethod]public void EditAction_Retrieves_Dinner_1_From_Repo_And_Countries_And_Sets_DinnerViewModel() { // Arrangevar controller = CreateDinnersControllerAs("someuser"); // ActViewResult result = controller.Edit(1) as ViewResult; // AssertDinnerFormViewModel model = result.ViewData.Model as DinnerFormViewModel;Assert.AreEqual(13, model.Countries.Count());}
8. http://nerddinner.codeplex.com/SourceControl/changeset/view/23425#439968 [TestMethod]public void EditAction_Retrieves_Dinner_1_From_Repo_And_Countries_And_Sets_DinnerViewModel() { // Arrangevar controller = CreateDinnersControllerAs("someuser"); // ActViewResultresult = controller.Edit(1) as ViewResult; // AssertDinnerFormViewModel model = result.ViewData.Model as DinnerFormViewModel;Assert.AreEqual(13, model.Countries.Count());}
9. [Fact] public void RsdReturnsValidRsdDoc() {FakeAreaServiceareaService = new FakeAreaService();areaService.StoredAreas.Add("test", new Oxite.Models.Area(false, DateTime.MinValue, null, null, Guid.NewGuid(), DateTime.MinValue, "test"));RouteCollection routes = new RouteCollection();routes.Add("Posts", new Route("", new MvcRouteHandler()));UrlHelper helper = new UrlHelper(new RequestContext(new FakeHttpContext(new Uri("http://oxite.net/"),"~/"), new RouteData()), routes); Site site = new Site() { Host = new Uri("http://oxite.net") };AreaController controller = new AreaController(site, areaService, null, null, null, null, null) { Url = helper };ContentResult result = controller.Rsd("test");Assert.NotNull(result);XDocumentrsdDoc = XDocument.Parse(result.Content);XNamespacersdNamespace = "http://archipelago.phrasewise.com/rsd";XElementrootElement = rsdDoc.Element(rsdNamespace + "rsd");Assert.NotNull(rootElement);Assert.NotNull(rootElement.Attribute("version"));Assert.Equal("1.0", rootElement.Attribute("version").Value);Assert.Equal("Oxite", rootElement.Descendants(rsdNamespace + "engineName").SingleOrDefault().Value);Assert.Equal("http://oxite.net", rootElement.Descendants(rsdNamespace + "engineLink").SingleOrDefault().Value);Assert.Equal("http://oxite.net/", rootElement.Descendants(rsdNamespace + "homePageLink").SingleOrDefault().Value);XElementapisElement = rootElement.Descendants(rsdNamespace + "apis").SingleOrDefault();Assert.NotNull(apisElement);Assert.Equal(1, apisElement.Elements().Count());XElementapiElement = apisElement.Elements().SingleOrDefault();Assert.NotNull(apiElement);Assert.Equal(rsdNamespace + "api", apiElement.Name);Assert.Equal("MetaWeblog", apiElement.Attribute("name").Value);Assert.Equal(areaService.StoredAreas["test"].ID.ToString("N"), apiElement.Attribute("blogID").Value);Assert.Equal("true", apiElement.Attribute("preferred").Value);Assert.Equal("http://oxite.net/MetaWeblog.svc", apiElement.Attribute("apiLink").Value); } http://oxite.codeplex.com/SourceControl/changeset/view/54721#419183
10. [Fact] public void RsdReturnsValidRsdDoc() {FakeAreaServiceareaService = new FakeAreaService();areaService.StoredAreas.Add("test", new Oxite.Models.Area(false, DateTime.MinValue, null, null, Guid.NewGuid(), DateTime.MinValue, "test"));RouteCollection routes = new RouteCollection();routes.Add("Posts", new Route("", new MvcRouteHandler()));UrlHelper helper = new UrlHelper(new RequestContext(new FakeHttpContext(new Uri("http://oxite.net/"),"~/"), new RouteData()), routes); Site site = new Site() { Host = new Uri("http://oxite.net") };AreaController controller = new AreaController(site, areaService, null, null, null, null, null) { Url = helper };ContentResult result = controller.Rsd("test");Assert.NotNull(result);XDocumentrsdDoc = XDocument.Parse(result.Content);XNamespacersdNamespace = "http://archipelago.phrasewise.com/rsd";XElementrootElement = rsdDoc.Element(rsdNamespace + "rsd");Assert.NotNull(rootElement);Assert.NotNull(rootElement.Attribute("version"));Assert.Equal("1.0", rootElement.Attribute("version").Value);Assert.Equal("Oxite", rootElement.Descendants(rsdNamespace + "engineName").SingleOrDefault().Value);Assert.Equal("http://oxite.net", rootElement.Descendants(rsdNamespace + "engineLink").SingleOrDefault().Value);Assert.Equal("http://oxite.net/", rootElement.Descendants(rsdNamespace + "homePageLink").SingleOrDefault().Value);XElementapisElement = rootElement.Descendants(rsdNamespace + "apis").SingleOrDefault();Assert.NotNull(apisElement);Assert.Equal(1, apisElement.Elements().Count());XElementapiElement = apisElement.Elements().SingleOrDefault();Assert.NotNull(apiElement);Assert.Equal(rsdNamespace + "api", apiElement.Name);Assert.Equal("MetaWeblog", apiElement.Attribute("name").Value);Assert.Equal(areaService.StoredAreas["test"].ID.ToString("N"), apiElement.Attribute("blogID").Value);Assert.Equal("true", apiElement.Attribute("preferred").Value);Assert.Equal("http://oxite.net/MetaWeblog.svc", apiElement.Attribute("apiLink").Value); } http://oxite.codeplex.com/SourceControl/changeset/view/54721#419183
11. http://grabbagoft.blogspot.com/2007/09/authoring-stories-with-nbehave-03.html [Story] public void Should_find_customers_by_name_when_name_matches() { Story story = new Story("List customers by name"); story.AsA("customer support staff") .IWant("to search for customers in a very flexible manner") .SoThat("I can find a customer record and provide meaningful support"); CustomerRepository repo = null; Customer customer = null; story.WithScenario("Find by name") .Given("a set of valid customers", delegate { repo = CreateDummyRepo(); }) .When("I ask for an existing name", "Joe Schmoe", delegate(string name) { customer = repo.FindByName(name); }) .Then("the correct customer is found and returned", delegate {Assert.That(customer.Name, Is.EqualTo("Joe Schmoe"));}); }
32. $: << ‘../NerdDinner/bin’ require ‘NerdDinner.dll’ Include NerdDinner::Controllers describe DinnersController, “when editing” do
33. it “returns countries where dinners can be hosted” do controller = DinnersController.new end
34. it “returns countries where dinners can be hosted” do controller = DinnersController.new(dinner_repos(dinners)) end
35. it “returns countries where dinners can be hosted” do controller = DinnersController.new(dinner_repos(dinners)) result = controller.Edit(1).ViewData.Model end
36. it “returns countries where dinners can be hosted” do controller = DinnersController.new(dinner_repos(dinners)) result = controller.Edit(1).ViewData.Model result.Countries.Count().should == test_data.length end RSpec has really powerful matchers
37. D:ourceControlerddinner-23425pecs>ispecDinnersController_specs.rb F 1) 'NerdDinner::Controllers::DinnersController when editing should return countries where dinners can be hosted' FAILED expected: 13, got: nil (using ==) ./DinnersController_specs.rb:8: Finished in 0.4824219 seconds 1 example, 1 failure
39. require ‘caricature’ def dinner_repos(test_data) IDinnerRepository.isolate(:FindUpcomingDinners) {returns test_data} End
40. def create_dinners(count=13) dinners = [] count.timesdo |i| dinners << Dinner.new(:country => “Value#{i}”) end end
41. describe DinnersController, "when editing" do let(:dinners) {create_dinners} let(:controller) {DinnersController.new(dinner_repos dinners)} it "returns countries where dinners can be hosted" do result = controller.Edit(dinners.first.id).view_model result.Countries.Count().should == dinners.length end end
42. result.Countries.Count().should == dinners.length result.Countries.shouldhave_same_count(dinners) module Matchers class CountEqual def initialize(expected) @expected = expected end def matches?(actual) actual.Count() == @expected.Count() end end def have_same_count(expected) CountEqual.new(expected) end end Duck Typing FTW!
43. describe DinnersController, “Managing dinner reservations” do let(:dinners) { valid_dinners } let(:controller) {DinnersController.new(dinner_repository dinners)} describe “when editing“it_should_behave_like “valid dinners” it "returns countries where dinners can be hosted" end describe “when saving“ do describe “the validation for invalid dinners” do let(:dinners) { bad_dinners(1) }it “should reject a dinner without a name” it “should reject a dinner without a email address” it “should accept a dinner if it has a name and email address” end describe “confirmation” do it “should send an email to the organiser once saved” end describe “valid dinners” do it “redirects to thank you page after completing" end end end
44. describe "NHibernate" do before do config = Configuration.new @cfg = config.configure(File.join(Dir.pwd, "nhibernate.config")) end it "can create session factory" do session_factory = @cfg.BuildSessionFactory() session_factory.should_notbe_nil end it "can create session" do session_factory = @cfg.BuildSessionFactory() session = session_factory.open_session session.should_notbe_nil end end
48. [Story] public void Should_find_customers_by_name_when_name_matches() { Story story = new Story("List customers by name"); story.AsA("customer support staff") .IWant("to search for customers in a very flexible manner") .SoThat("I can find a customer record and provide meaningful support"); CustomerRepository repo = null; Customer customer = null; story.WithScenario("Find by name") .Given("a set of valid customers", delegate { repo = CreateDummyRepo(); }) .When("I ask for an existing name", "Joe Schmoe", delegate(string name) { customer = repo.FindByName(name); }) .Then("the correct customer is found and returned", delegate {Assert.That(customer.Name, Is.EqualTo("Joe Schmoe"));}); }
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
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
51. D:ourceControlerddinner-23425eatures>cucumber list.feature 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 support Scenario: Find by name # list.feature:6 Given a set of valid customers # list.feature:7 When I ask for an existing name # list.feature:8 Then the correct customer is found and returned # list.feature:9 1 scenario (1 undefined) 3 steps (3 undefined) 0m0.020s You can implement step definitions for undefined steps with these snippets: Given /^a set of valid customers$/ do pending # express the regexp above with the code you wish you had end When /^I ask for an existing name$/ do pending # express the regexp above with the code you wish you had end Then /^the correct customer is found and returned$/ do pending # express the regexp above with the code you wish you had end
52. NOT BEST PRACTICE!! Given /^a set of valid customers$/ do @repo = CreateDummyRepo()endWhen /^I ask for an existing name$/ do @customer = @repo.FindByName("Joe Schmoe")endThen /^the correct customer is found and returned$/ do @customer.Name.should == "Joe Schmoe“end
53. Given /^customer “([^amp;quot;]*)” $/ do |name| @repo = CustomerRepository.new(Customer.new(:name => name)endWhen /^I search for customer “([^amp;quot;]*)”$/ do |name| @customer = @repo.FindByName(name)endThen /^”([^amp;quot;]*)” should be found and returned$/ do |name| @customer.Name.should == nameend
64. 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 amp;quot;(.*)amp;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 amp;quot;(.*)amp;quot; in the results$")] publicvoidResultsContain(stringexpectedResult) { Assert.That(_browser.ContainsText(expectedResult)); } } }
65. Given /^(?:I'm on|I go to) the search page$/ do visit 'http://www.google.com' end When /^I search for "([^amp;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 amp;quot;(.*)amp;quot; in the results$/ do|text| response.should contain(text) end