SlideShare a Scribd company logo
1 of 79
Testing C# and ASP.net using Ruby Meerkatalyst @Ben_HallBen@BenHall.me.ukBlog.BenHall.me.uk
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
How we can apply Ruby testing techniques to C#	- In mindset	- In practice 1|	Object Level testing2|	Systems testing
WHY? http://www.flickr.com/photos/atomicpuppy/2132073976/
VALUE
Realised Ruby doesn’t have as many problems as .net
Natural Language
Test Driven Development TDD
I love writing tests upfront
Not sure about implementation According to various TDD books blogs
Help with an initial design but what about long term?
“Unit”
Behaviour Driven Development BDD
Shift focus Final Intent
Code Coverage
Context Specification
RSpec http://www.flickr.com/photos/dodgsun/467076780/
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
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
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
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
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
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
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
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
http://www.flickr.com/photos/buro9/298994863/ WHY RUBY?
[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();    }
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
Consider your test suite containing > 500 tests Each test matters. But each problem hurts more
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“
Include   additional functionality require ‘nhibernate_helpers’require ‘product_creation_extensions’require  ‘customer_creation_extensions’describe ProductController do
model.Categories.to_a.Count.should == 1 model.Categories.should have(1) module Matchers     class CountCheck     def initialize(expected)       @expected = expected     end     def matches?(actual) actual.to_a.Count() == @expected     end   end   def have(expected) CountCheck.new(expected)   end end Duck Typing FTW!
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
INTEGRATION TESTS http://www.flickr.com/photos/gagilas/2659695352/
I’m against integration tests Or at least 90% of them
Multiple Collaborators
Unmanageable nightmare
12 hour execution time?
5174 passed, 491 failed, 94 skipped
“Tests aren’t failing because of defects”
‘Nearly’ end-to-end While knowing about everything in the middle...
Becomes a pain to refactor
FEAR
FEAR
UNIT testing frameworks
Bad organisation
Increased duplication Overlap Unit Tests Integration Tests UI System Acceptance Tests Overlap
STOPPED
Unit Tests Acceptance Tests
Outside-in Development
Cucumber http://www.flickr.com/photos/vizzzual-dot-com/2738586453/
Feature: Creating a schedule 	In Order to book meetings 	The manager 	Needs to be able to view a teams calendar Scenario: View calendar of another view Given “Bob” has a public calendar When the manager views “Bob”’s calendar Then an empty calendar should be shown
Given /^”([^quot;]*)” has a public calendar$/ do |user|    pending End When /^ the manager views “([^quot;]*)”’s calendar$/ do |user|    pending End Then /^ an empty calendar should be shown $/ do    pending end
Thanks to TekPub for Kona sample
Thanks to TekPub for Kona sample
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"
WebRat http://www.flickr.com/photos/whatwhat/22624256/
visit click_link fill_in click_button check and uncheck choose select attach_file
Given /^the featured product "([^quot;]*)"$/ do |product_name| Product.createproduct_name, ‘featured’ end
When /^I visit the homepage$/ do   visit url + '/' end
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
Dynamically replaced env_selenium.rb def url   "http://www.website.local" end Webrat.configure do |config| config.mode = :selenium config.application_framework = :external config.selenium_browser_key = get_browser_key   puts "Executing tests using the browser #{config.selenium_browser_key}" end def get_browser_key()   command = "*firefox"   command = ENV['BROWSER'] if ENV['BROWSER']   return command end
cucumber --profile selenium browser=*firefox cucumber --profile selenium browser=*safari cucumber --profile selenium browser=*iexplore cucumber --profile selenium browser=*googlechrome
cucumber --profile webrat HEADLESS BROWSING BY REPLACING ENV.RB
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"   |
Before do open_connection empty_database end at_exit do empty_database end Multiple Hooks
Multiple extension frameworks Test command line applications Test Silverlightlex Test WPF based desktop applications Execute in parallel across multiple machines
HUGE RE-USE == VALUE
http://www.flickr.com/photos/leon_homan/2856628778/
Focus on finding true value Look at other communities for advice, support and inspiration
@Ben_Hall Ben@BenHall.me.uk Blog.BenHall.me.uk http://lolcatgenerator.com/lolcat/120/
Lonestar
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));         }     } }
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
Software Recommended: IronRuby Ruby Cucumber Rspec WebRat mechanize Selenium RC selenium-client Caricature activerecord-sqlserver-adapter Optional: XSP Mono JetBrain’sRubyMine JRuby Capybara Celerity Active record  active-record-model-generator Faker Guid
Useful Links http://www.github.com/BenHall http://blog.benhall.me.uk http://stevehodgkiss.com/2009/11/14/using-activerecord-migrator-standalone-with-sqlite-and-sqlserver-on-windows.html http://www.testingaspnet.com http:// http://msdn.microsoft.com/en-us/magazine/dd434651.aspx http://msdn.microsoft.com/en-us/magazine/dd453038.aspx http://www.cukes.info
SQL Server and Ruby gem install activerecord-sqlserver-adapter Download dbi-0.2.2.zip  Extract dbdDO.rb to rubyite_ruby.8BDDO.rb

More Related Content

What's hot

5 Reasons To Love CodeIgniter
5 Reasons To Love CodeIgniter5 Reasons To Love CodeIgniter
5 Reasons To Love CodeIgniter
nicdev
 
Intro to-rails-webperf
Intro to-rails-webperfIntro to-rails-webperf
Intro to-rails-webperf
New Relic
 

What's hot (20)

Angularjs
AngularjsAngularjs
Angularjs
 
Solid angular
Solid angularSolid angular
Solid angular
 
Magento Indexes
Magento IndexesMagento Indexes
Magento Indexes
 
Kiss PageObjects [01-2017]
Kiss PageObjects [01-2017]Kiss PageObjects [01-2017]
Kiss PageObjects [01-2017]
 
RESTful services and OAUTH protocol in IoT
RESTful services and OAUTH protocol in IoTRESTful services and OAUTH protocol in IoT
RESTful services and OAUTH protocol in IoT
 
Gae
GaeGae
Gae
 
AngularJS best-practices
AngularJS best-practicesAngularJS best-practices
AngularJS best-practices
 
5 Reasons To Love CodeIgniter
5 Reasons To Love CodeIgniter5 Reasons To Love CodeIgniter
5 Reasons To Love CodeIgniter
 
Intro to-rails-webperf
Intro to-rails-webperfIntro to-rails-webperf
Intro to-rails-webperf
 
Controller Testing: You're Doing It Wrong
Controller Testing: You're Doing It WrongController Testing: You're Doing It Wrong
Controller Testing: You're Doing It Wrong
 
AtlasCamp 2015: Web technologies you should be using now
AtlasCamp 2015: Web technologies you should be using nowAtlasCamp 2015: Web technologies you should be using now
AtlasCamp 2015: Web technologies you should be using now
 
React Native Workshop - React Alicante
React Native Workshop - React AlicanteReact Native Workshop - React Alicante
React Native Workshop - React Alicante
 
Angular JS - Introduction
Angular JS - IntroductionAngular JS - Introduction
Angular JS - Introduction
 
I Love codeigniter, You?
I Love codeigniter, You?I Love codeigniter, You?
I Love codeigniter, You?
 
Extend sdk
Extend sdkExtend sdk
Extend sdk
 
Automation Abstractions: Page Objects and Beyond
Automation Abstractions: Page Objects and BeyondAutomation Abstractions: Page Objects and Beyond
Automation Abstractions: Page Objects and Beyond
 
Introduction to Unit Tests and TDD
Introduction to Unit Tests and TDDIntroduction to Unit Tests and TDD
Introduction to Unit Tests and TDD
 
Easy tests with Selenide and Easyb
Easy tests with Selenide and EasybEasy tests with Selenide and Easyb
Easy tests with Selenide and Easyb
 
Understanding angular js
Understanding angular jsUnderstanding angular js
Understanding angular js
 
Ajax Applications with RichFaces and JSF 2
Ajax Applications with RichFaces and JSF 2Ajax Applications with RichFaces and JSF 2
Ajax Applications with RichFaces and JSF 2
 

Viewers also liked

Viewers also liked (12)

Unit 4 Project
Unit 4 ProjectUnit 4 Project
Unit 4 Project
 
Tìm hiểu về website
Tìm hiểu về websiteTìm hiểu về website
Tìm hiểu về website
 
Sinh hoat CLB tin hoc Komaba lan 2 - Phat bieu cua Ngoc
Sinh hoat CLB tin hoc Komaba lan 2 - Phat bieu cua NgocSinh hoat CLB tin hoc Komaba lan 2 - Phat bieu cua Ngoc
Sinh hoat CLB tin hoc Komaba lan 2 - Phat bieu cua Ngoc
 
Asp net
Asp netAsp net
Asp net
 
Bai giang-lap-trinh-web-bang-asp
Bai giang-lap-trinh-web-bang-aspBai giang-lap-trinh-web-bang-asp
Bai giang-lap-trinh-web-bang-asp
 
Asp
AspAsp
Asp
 
Controls
ControlsControls
Controls
 
Intro To Asp Net And Web Forms
Intro To Asp Net And Web FormsIntro To Asp Net And Web Forms
Intro To Asp Net And Web Forms
 
Note d'intention
Note d'intentionNote d'intention
Note d'intention
 
Introduction to ASP.NET
Introduction to ASP.NETIntroduction to ASP.NET
Introduction to ASP.NET
 
Cookies and sessions
Cookies and sessionsCookies and sessions
Cookies and sessions
 
Developing an ASP.NET Web Application
Developing an ASP.NET Web ApplicationDeveloping an ASP.NET Web Application
Developing an ASP.NET Web Application
 

Similar to Testing C# and ASP.net using Ruby

OSDC 2009 Rails Turtorial
OSDC 2009 Rails TurtorialOSDC 2009 Rails Turtorial
OSDC 2009 Rails Turtorial
Yi-Ting Cheng
 
Controllers & actions
Controllers & actionsControllers & actions
Controllers & actions
Eyal Vardi
 

Similar to Testing C# and ASP.net using Ruby (20)

Ride on the Fast Track of Web with Ruby on Rails- Part 2
Ride on the Fast Track of Web with Ruby on Rails- Part 2Ride on the Fast Track of Web with Ruby on Rails- Part 2
Ride on the Fast Track of Web with Ruby on Rails- Part 2
 
Catalog display
Catalog displayCatalog display
Catalog display
 
The Rails Way
The Rails WayThe Rails Way
The Rails Way
 
Testing ASP.net Web Applications using Ruby
Testing ASP.net Web Applications using RubyTesting ASP.net Web Applications using Ruby
Testing ASP.net Web Applications using Ruby
 
OSDC 2009 Rails Turtorial
OSDC 2009 Rails TurtorialOSDC 2009 Rails Turtorial
OSDC 2009 Rails Turtorial
 
mean stack
mean stackmean stack
mean stack
 
AngularJs-training
AngularJs-trainingAngularJs-training
AngularJs-training
 
Introduction to ASP.NET MVC
Introduction to ASP.NET MVCIntroduction to ASP.NET MVC
Introduction to ASP.NET MVC
 
Angular JS2 Training Session #2
Angular JS2 Training Session #2Angular JS2 Training Session #2
Angular JS2 Training Session #2
 
Continuous Quality
Continuous QualityContinuous Quality
Continuous Quality
 
ActiveWeb: Chicago Java User Group Presentation
ActiveWeb: Chicago Java User Group PresentationActiveWeb: Chicago Java User Group Presentation
ActiveWeb: Chicago Java User Group Presentation
 
Course CodeSchool - Shaping up with Angular.js
Course CodeSchool - Shaping up with Angular.jsCourse CodeSchool - Shaping up with Angular.js
Course CodeSchool - Shaping up with Angular.js
 
Introduction to Django
Introduction to DjangoIntroduction to Django
Introduction to Django
 
01 startoff angularjs
01 startoff angularjs01 startoff angularjs
01 startoff angularjs
 
Javascript first-class citizenery
Javascript first-class citizeneryJavascript first-class citizenery
Javascript first-class citizenery
 
Wt unit 5
Wt unit 5Wt unit 5
Wt unit 5
 
SharePoint Saturday Atlanta 2015
SharePoint Saturday Atlanta 2015SharePoint Saturday Atlanta 2015
SharePoint Saturday Atlanta 2015
 
Codegnitorppt
CodegnitorpptCodegnitorppt
Codegnitorppt
 
Spring MVC
Spring MVCSpring MVC
Spring MVC
 
Controllers & actions
Controllers & actionsControllers & actions
Controllers & actions
 

More from Ben Hall

More from Ben Hall (20)

The Art Of Documentation - NDC Porto 2022
The Art Of Documentation - NDC Porto 2022The Art Of Documentation - NDC Porto 2022
The Art Of Documentation - NDC Porto 2022
 
The Art Of Documentation for Open Source Projects
The Art Of Documentation for Open Source ProjectsThe Art Of Documentation for Open Source Projects
The Art Of Documentation for Open Source Projects
 
Three Years of Lessons Running Potentially Malicious Code Inside Containers
Three Years of Lessons Running Potentially Malicious Code Inside ContainersThree Years of Lessons Running Potentially Malicious Code Inside Containers
Three Years of Lessons Running Potentially Malicious Code Inside Containers
 
Containers without docker
Containers without dockerContainers without docker
Containers without docker
 
Deploying windows containers with kubernetes
Deploying windows containers with kubernetesDeploying windows containers with kubernetes
Deploying windows containers with kubernetes
 
The Art of Documentation and Readme.md for Open Source Projects
The Art of Documentation and Readme.md for Open Source ProjectsThe Art of Documentation and Readme.md for Open Source Projects
The Art of Documentation and Readme.md for Open Source Projects
 
How Secure Are Docker Containers?
How Secure Are Docker Containers?How Secure Are Docker Containers?
How Secure Are Docker Containers?
 
The Challenges of Becoming Cloud Native
The Challenges of Becoming Cloud NativeThe Challenges of Becoming Cloud Native
The Challenges of Becoming Cloud Native
 
Scaling Docker Containers using Kubernetes and Azure Container Service
Scaling Docker Containers using Kubernetes and Azure Container ServiceScaling Docker Containers using Kubernetes and Azure Container Service
Scaling Docker Containers using Kubernetes and Azure Container Service
 
The art of documentation and readme.md
The art of documentation and readme.mdThe art of documentation and readme.md
The art of documentation and readme.md
 
Experimenting and Learning Kubernetes and Tensorflow
Experimenting and Learning Kubernetes and TensorflowExperimenting and Learning Kubernetes and Tensorflow
Experimenting and Learning Kubernetes and Tensorflow
 
Running .NET on Docker
Running .NET on DockerRunning .NET on Docker
Running .NET on Docker
 
Real World Lessons on the Pain Points of Node.JS Application
Real World Lessons on the Pain Points of Node.JS ApplicationReal World Lessons on the Pain Points of Node.JS Application
Real World Lessons on the Pain Points of Node.JS Application
 
Tips on solving E_TOO_MANY_THINGS_TO_LEARN with Kubernetes
Tips on solving E_TOO_MANY_THINGS_TO_LEARN with KubernetesTips on solving E_TOO_MANY_THINGS_TO_LEARN with Kubernetes
Tips on solving E_TOO_MANY_THINGS_TO_LEARN with Kubernetes
 
Deploying applications to Windows Server 2016 and Windows Containers
Deploying applications to Windows Server 2016 and Windows ContainersDeploying applications to Windows Server 2016 and Windows Containers
Deploying applications to Windows Server 2016 and Windows Containers
 
The How and Why of Windows containers
The How and Why of Windows containersThe How and Why of Windows containers
The How and Why of Windows containers
 
Lessons from running potentially malicious code inside containers
Lessons from running potentially malicious code inside containersLessons from running potentially malicious code inside containers
Lessons from running potentially malicious code inside containers
 
Deploying Windows Containers on Windows Server 2016
Deploying Windows Containers on Windows Server 2016Deploying Windows Containers on Windows Server 2016
Deploying Windows Containers on Windows Server 2016
 
Learning Patterns for the Overworked Developer
Learning Patterns for the Overworked DeveloperLearning Patterns for the Overworked Developer
Learning Patterns for the Overworked Developer
 
Real World Lessons on the Pain Points of Node.js Applications
Real World Lessons on the Pain Points of Node.js ApplicationsReal World Lessons on the Pain Points of Node.js Applications
Real World Lessons on the Pain Points of Node.js Applications
 

Recently uploaded

Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
panagenda
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
?#DUbAI#??##{{(☎️+971_581248768%)**%*]'#abortion pills for sale in dubai@
 

Recently uploaded (20)

Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024Manulife - Insurer Innovation Award 2024
Manulife - Insurer Innovation Award 2024
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
Automating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps ScriptAutomating Google Workspace (GWS) & more with Apps Script
Automating Google Workspace (GWS) & more with Apps Script
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
GenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdfGenAI Risks & Security Meetup 01052024.pdf
GenAI Risks & Security Meetup 01052024.pdf
 
Real Time Object Detection Using Open CV
Real Time Object Detection Using Open CVReal Time Object Detection Using Open CV
Real Time Object Detection Using Open CV
 
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, AdobeApidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
Apidays New York 2024 - Scaling API-first by Ian Reasor and Radu Cotescu, Adobe
 
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost SavingRepurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
 
AWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of TerraformAWS Community Day CPH - Three problems of Terraform
AWS Community Day CPH - Three problems of Terraform
 
Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024Partners Life - Insurer Innovation Award 2024
Partners Life - Insurer Innovation Award 2024
 
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
Apidays New York 2024 - The Good, the Bad and the Governed by David O'Neill, ...
 
Why Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire businessWhy Teams call analytics are critical to your entire business
Why Teams call analytics are critical to your entire business
 
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdfUnderstanding Discord NSFW Servers A Guide for Responsible Users.pdf
Understanding Discord NSFW Servers A Guide for Responsible Users.pdf
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data DiscoveryTrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
TrustArc Webinar - Unlock the Power of AI-Driven Data Discovery
 
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
+971581248768>> SAFE AND ORIGINAL ABORTION PILLS FOR SALE IN DUBAI AND ABUDHA...
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
Exploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone ProcessorsExploring the Future Potential of AI-Enabled Smartphone Processors
Exploring the Future Potential of AI-Enabled Smartphone Processors
 
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot TakeoffStrategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
Strategize a Smooth Tenant-to-tenant Migration and Copilot Takeoff
 

Testing C# and ASP.net using Ruby

  • 1. Testing C# and ASP.net using Ruby Meerkatalyst @Ben_HallBen@BenHall.me.ukBlog.BenHall.me.uk
  • 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
  • 3. How we can apply Ruby testing techniques to C# - In mindset - In practice 1| Object Level testing2| Systems testing
  • 6. Realised Ruby doesn’t have as many problems as .net
  • 9. I love writing tests upfront
  • 10. Not sure about implementation According to various TDD books blogs
  • 11. Help with an initial design but what about long term?
  • 13.
  • 19.
  • 20. 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
  • 21. 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
  • 22. 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
  • 23. 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
  • 24. 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
  • 25. 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
  • 26. 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
  • 27. 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
  • 29. [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(); }
  • 30. 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
  • 31. Consider your test suite containing > 500 tests Each test matters. But each problem hurts more
  • 32. 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“
  • 33. Include additional functionality require ‘nhibernate_helpers’require ‘product_creation_extensions’require ‘customer_creation_extensions’describe ProductController do
  • 34. model.Categories.to_a.Count.should == 1 model.Categories.should have(1) module Matchers class CountCheck def initialize(expected) @expected = expected end def matches?(actual) actual.to_a.Count() == @expected end end def have(expected) CountCheck.new(expected) end end Duck Typing FTW!
  • 35. 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
  • 37. I’m against integration tests Or at least 90% of them
  • 41. 5174 passed, 491 failed, 94 skipped
  • 42. “Tests aren’t failing because of defects”
  • 43. ‘Nearly’ end-to-end While knowing about everything in the middle...
  • 44. Becomes a pain to refactor
  • 45. FEAR
  • 46. FEAR
  • 49. Increased duplication Overlap Unit Tests Integration Tests UI System Acceptance Tests Overlap
  • 54. Feature: Creating a schedule In Order to book meetings The manager Needs to be able to view a teams calendar Scenario: View calendar of another view Given “Bob” has a public calendar When the manager views “Bob”’s calendar Then an empty calendar should be shown
  • 55. Given /^”([^quot;]*)” has a public calendar$/ do |user| pending End When /^ the manager views “([^quot;]*)”’s calendar$/ do |user| pending End Then /^ an empty calendar should be shown $/ do pending end
  • 56. Thanks to TekPub for Kona sample
  • 57. Thanks to TekPub for Kona sample
  • 58. 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"
  • 60. visit click_link fill_in click_button check and uncheck choose select attach_file
  • 61. Given /^the featured product "([^quot;]*)"$/ do |product_name| Product.createproduct_name, ‘featured’ end
  • 62. When /^I visit the homepage$/ do visit url + '/' end
  • 63. 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
  • 64. Dynamically replaced env_selenium.rb def url "http://www.website.local" end Webrat.configure do |config| config.mode = :selenium config.application_framework = :external config.selenium_browser_key = get_browser_key puts "Executing tests using the browser #{config.selenium_browser_key}" end def get_browser_key() command = "*firefox" command = ENV['BROWSER'] if ENV['BROWSER'] return command end
  • 65. cucumber --profile selenium browser=*firefox cucumber --profile selenium browser=*safari cucumber --profile selenium browser=*iexplore cucumber --profile selenium browser=*googlechrome
  • 66. cucumber --profile webrat HEADLESS BROWSING BY REPLACING ENV.RB
  • 67. 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" |
  • 68. Before do open_connection empty_database end at_exit do empty_database end Multiple Hooks
  • 69. Multiple extension frameworks Test command line applications Test Silverlightlex Test WPF based desktop applications Execute in parallel across multiple machines
  • 70. HUGE RE-USE == VALUE
  • 72. Focus on finding true value Look at other communities for advice, support and inspiration
  • 73. @Ben_Hall Ben@BenHall.me.uk Blog.BenHall.me.uk http://lolcatgenerator.com/lolcat/120/
  • 75. 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));         }     } }
  • 76. 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
  • 77. Software Recommended: IronRuby Ruby Cucumber Rspec WebRat mechanize Selenium RC selenium-client Caricature activerecord-sqlserver-adapter Optional: XSP Mono JetBrain’sRubyMine JRuby Capybara Celerity Active record active-record-model-generator Faker Guid
  • 78. Useful Links http://www.github.com/BenHall http://blog.benhall.me.uk http://stevehodgkiss.com/2009/11/14/using-activerecord-migrator-standalone-with-sqlite-and-sqlserver-on-windows.html http://www.testingaspnet.com http:// http://msdn.microsoft.com/en-us/magazine/dd434651.aspx http://msdn.microsoft.com/en-us/magazine/dd453038.aspx http://www.cukes.info
  • 79. SQL Server and Ruby gem install activerecord-sqlserver-adapter Download dbi-0.2.2.zip Extract dbdDO.rb to rubyite_ruby.8BDDO.rb

Editor's Notes

  1. Cost 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
  2. 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
  3. Cleaner, more focused designDefining how it’s meant to workProvide documentation for myself and team members over coming monthsyears of projectRefactoring
  4. Naming Implementation might go though multiple interactions until I reach my desired behaviour.
  5. Or at least, that’s what I would like..Net Problems- Unit doesn’t represent the concept of real world software - Legacy where nothing is a unit - Mentoring
  6. System brings together different parts to solve a particular problem
  7. 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
  8. Feature Coverage
  9. Often forgot in the .Net world...Started to come more maintain stream thanks to Aaron Jenson and Scott BellwareBounded contexts
  10. 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.
  11. get_div_id == “Design UI for Testability”
  12. get_div_id == “Design UI for Testability”
  13. get_div_id == “Design UI for Testability”
  14. get_div_id == “Design UI for Testability”
  15. get_div_id == “Design UI for Testability”