Showing posts with label testing. Show all posts
Showing posts with label testing. Show all posts

How to increase the Code Coverage in 2 easy steps

As a developer you come to the point in time where a manager asks you to have at least 80% Code Coverage in your code.

Manager 
Photo Credit: Sam Foster

All managers love to see numbers, especially big increasing numbers.
I love big numbers too!

Use Scrum + Continuous Delivery to build the right thing

How do you get feedback?
Figure: How and how often do you get feedback?  flickr
The two topics “Scrum” and “Continuous Delivery” kept me very excited in the last years, which resulted in two presentations and a whitepaper for scrum.org.

First steps with Machine.Specifications (BDD framework)

Old machine. Where is the specification?
Figure: How do you specify this machine?

As you may have read in my previous blog post: On the road to BDD… Or… to see the light, I am dabbling more and more into the ATDD / BDD world.

These are my impressions from Machine.Specifications.
BTW: Gread video from JP Boodhoo about Getting up and running with MSpec

Code52 Show and Tell: My pet project CopyCat - Lessons learned

CopyCat – A big fat cat walking and waltzing the internetz

Figure: CopyCat – A big fat cat walking and waltzing the internetz
 

I am a pretty normal geek. At least I think I am normal and a geek. I see geeks as people (yes really) that want to play with things, discover new things and build things. When geeks play with things they discover new things quite often.
(Similar story heard and “adapted” from Scott Hanselman) 
After I ‘ve discovered something I want to scream it out to someone:

“Look at this dude!! Isn’t that awesome???”

A normal reaction that you get from a non-geek:

“Wow… Is this showing the weather in form of colors that you could just get by watching out the window?”

This is the pattern for the reaction that you normally get
“Wow… Is this <something> that does <somethingUselessAtBeginning> that you could just get by doing <somethingElse>?”

Silverlight - Testing the untestable

Another limitation of testing Silverlight that me and one of my workmates ran into with mstest and VS2010 is documented below.
OOP especially Polymorphism help us here though.

We try to test a method that takes an ObservableCollection as input parameter.
I would like to leave the discussion about whether a method with a parameter of type "ObservableCollection" is a good idea or not to another day… Smile

This is the method we want to write some tests around

On the road to BDD… Or… to see the light

If you are a regular reader of this little blog in the middle of the internet, you might have realized that I am keen on “all things testing”. This is just a little experience report on my journey to better testing and getting everyone involved in the discussion about what we are building with our codez.

image
Figure: Everyone get together and collaborate

Fast = $$$ How do you make sure to have a fast application?

Speed = $$$
Many articles on the web, books and statistics tell us that “faster = better” and even more important: faster = more revenue.

For Google an increase in page load time from 0.4 second to 0.9 seconds decreased traffic and ad revenues by 20%.
For Amazon every 100 ms increase in load times decreased sales with 1%.

 

Also Google uses site speed in their web search ranking. So make sure to optimize your website for speed as per my other blog post.

Is Web Performance Optimization (WPO) something for you?

The broken window theory in the real world

I used to live in beautiful sunny Neutral Bay, Sydney where I walked along Bent Street every day. I moved back to Europe at the end of this July and just found this in my Draft blog folder..
I experienced the "broken window theory" myself, in front of my door.

image image image
18 February
23 February 1 March

Avoid the debugger like the pest

In this post I want to explain why I don't like debugging, and prefer instead to use unit testing where I work in tiny sections.
To put this post in context, can first I encourage you to read:

I wait here in the meantime Winking smile

"Continuously" testing with Visual Studio 2010

I used the following notes as guide line for my talk Sydney ALT.NET, and just post them here for future reference…
Had a great night @ the user group and interesting insights into stackoverflow from Sam Saffron.

 

An important aspect of Agile is the feedback loop or in other words: We want short feedback cycles.
Check out Scott Ambler post for why those feedback loops are so important in Agile http://www.ambysoft.com/essays/whyAgileWorksFeedback.html

Code contracts - Is it only about argument validation?

*Updated* 3 April 2011: Update how to enable Intellisense for code contracts

 

There are more and more articles coming out about Code Contracts. Some of them talk only about input validation and miss the goal of Code Contracts. What else can we do with Code Contracts?

image
Figure: Real world validation message


Microsoft DevLabs says: Code Contracts express coding assumptions

 

question_and_answer[5] What are coding assumptions?

Naming of unit tests - Should we follow a guideline?

I had this very interesting discussion with some fellow developers and post here a quick Q&A

Question
>>If a unit test fails - do you fix it by looking at the name of the test, or do you fix it by looking at the unit test?

Answer
By looking at the name of the unit test, you know what is broken, as per definition of "Unit test". (A unit test should test only 1 small unit of work)
So you don't need to actually read and understand the test, which saves you HEAPS of time!!

If you have an exception with stack trace you probably start with that Winking smile

 

Question
>>If you have to change the unit test code, do you then update the name, because it is now out of sync?

Answer
You should ask yourself why you change the unit test code

  1. If the unit test code has a bug, than you *don't need* to change the name.
    Fix the test
  2. If the production code is broken, you *don't need* to change the name.
    Fix the production code
  3. If the requirements change, you *need* to change the name or delete the test, because the requirements changed
    Because your "tests" act as documentation, the name change is VERY welcome

 

I think this misunderstanding comes from mixing up: "Unit test" and all other tests, like "Integration test", "System test" and "End to End test"
There is a big difference between a "Unit test" and all other tests, see Definition of Unit test

image

Developer Blog Banter - How do you test your applications?

David started a nice article series: The developer banter - this time about testing

"How do you organise your tests. Do you separate your unit tests, integration tests and UI tests into separate projects?
Do you do anything specific to keep track of your tests?
What naming conventions do you use? Do you run them before a check in or is that what the build server is for?"

Why are *automated tests* so important?

*Updated* 4 November 2010: Added another reason for writing tests: Documentation


Reasons why you should write *tests* in the first place

  1. You get a bug report and want to proof when the bug is fixed
    This is a good practice before fixing bugs
  2. You implement a new feature and write a test beforehand to see when the new feature is done
  3. You want prevent regression
    Changes in your code will break other code. So you have a test around it to know if everything is still green (=OK)
    As an agile developer you change code all the time, either because
    1. You do TDD
    2. You follow the Boy scout rule (Leave the campground cleaner than you found it) and refactor your code
    3. Your client/customer changes his mind (which is even more likely)
  4. Documentation goes out of date sooner or later. Tests document how the system works and additionally they are executable

How to unit test a WCF service?

I am *very* keen on automating tests, so I was looking into unit testing a WCF service.

If I say "unit test", I mean a fast, in-memory, independent and automated test of a functional unit-of-work in the system.
Unit of work is at maximum one method (on my projects)
With thanks to Roy Osherove

Why should we unit test a WCF service?

"Hidden" shortcuts for testers in Visual Studio

Like most of us, I learned the following shortcuts from the menu
image
Figure: VS Run tests menu items with shortcuts

Ctrl+R,T Run tests in current context
Ctrl+R,A Run all tests in solution
Ctrl+R,Y Run all impacted tests

with their corresponding Debug Mode, by using <Ctrl> for the second keystroke. E.g. Ctrl+R,Ctrl+T Debug tests in current context

Today I discovered these additional shortcuts.
I discovered those by changing some shortcuts from using MSTest to TestDriven, as per suggestion from RBanks54 (which rocks BTW, both)

Spot the bug … and avoid the bug with a unit test helper class

I have a class with the following code. This looks OK but isn’t…

 

    public class Lot : INotifyPropertyChanged
    {

        private string _actualHighestBidder;
        
       
        
        public string ActualHighestBidder
        {
            get
            {
                return _actualHighestBidder;
            }
            set
            {
                if (_actualHighestBidder.Equals(value) != true)
                {
                    _actualHighestBidder = value;
                    RaisePropertyChanged("ActualHighestBidder");
                }
            }
        }

     -- SNIP -- Implementation of INotifyPropertyChanged omitted

Spot the problem in the code above!!!

 

Scroll down

…

 

 

Scroll down

…

 

 

 

The private variable “_actualHighestBidder” is a string and is null.
Calling Equals on a null variable causes an annoying NullReferenceException.

 

 

There are 2 ways to solve this

1. Initialize your private backed field

        private string _actualHighestBidder = string.Empty;

2. Test for null

 public string ActualHighestBidder
        {
            get
            {
                return _actualHighestBidder;
            }
            set
            {
                if ((_actualHighestBidder == null || _actualHighestBidder.Equals(value) != true))
                {
                    _actualHighestBidder = value;
                    RaisePropertyChanged("ActualHighestBidder");
                }
            }
        }

I prefer the first method
but
how do we make sure we are not introducing this bugs in the future?

Note
This bug is very annoying, because we get this exception at runtime!

 

Idea!
image
Set all properties to some values with reflection

So that we can have a test like this

        [TestMethod()]
        public void LotProperties_SetAllProperties_NoException()
        {
            Lot target = new Lot();

            target.SetAllPublicProperties();
            target.GetAllPublicProperties();
            
            Assert.IsNotNull(target);
        }

 

My implementation of these 2 methods look like the below…

The method SetAllPublicProperties, sets all properties via Reflection
And the method GetAllPublicProperties does the same but tries to read the values!!

using System;
using System.Diagnostics;
using System.Reflection;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace Tests.Integration.Utils
{
    public static class ReflectionHelper
    {



        public static void SetAllPublicProperties(this object target)
        {
            Type targetType = target.GetType();

            foreach (MemberInfo memberInfo in targetType.GetProperties())
            {
                //Debug.WriteLine("memberInfo: " + memberInfo.ToString());

                PropertyInfo propertyInfo = memberInfo as PropertyInfo;
                if (propertyInfo != null)
                {
                    //Debug.WriteLine("propertyInfo: field " + propertyInfo.ToString());

                    if (propertyInfo.CanWrite)
                    {
                        MethodInfo setMethod = propertyInfo.GetSetMethod();


                        if (propertyInfo.PropertyType == typeof(string))
                        {
                            setMethod.Invoke(target, new object[] { "String parameter" });

                        }
                        else if (propertyInfo.PropertyType == typeof(bool))
                        {
                            setMethod.Invoke(target, new object[] { true });
                        }

                        else if (propertyInfo.PropertyType == typeof(Single))
                        {
                            setMethod.Invoke(target, new object[] { 123 });
                        }
                        else if (propertyInfo.PropertyType == typeof(Single?))
                        {
                            setMethod.Invoke(target, new object[] { null });
                            setMethod.Invoke(target, new object[] { (Single?)123 });
                        }
                        else
                        {
                            Assert.Fail("Generic Poperty setter not implemented for type: " + propertyInfo.PropertyType);
                        }
                    }
                }
            }
        }



        public static void GetAllPublicProperties(this object target)
        {
            Type targetType = target.GetType();

            foreach (MemberInfo memberInfo in targetType.GetProperties()) //System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.
            {
                //Debug.WriteLine("memberInfo: " + memberInfo.ToString());

                PropertyInfo propertyInfo = memberInfo as PropertyInfo;
                if (propertyInfo != null)
                {
                    //Debug.WriteLine("propertyInfo: field " + propertyInfo.ToString());

                    if (propertyInfo.CanRead)
                    {
                        MethodInfo getMethod = propertyInfo.GetGetMethod();

                        object readValue = getMethod.Invoke(target, null);

                        Debug.WriteLine("Value from property: " + readValue);

                    }
                }
            }
        }
    }
}

 

Use it and extend it to all your needed types!

TDD with C# 4 dynamic keyword

*Updated* 2 Mai 2011: The "dynamic" keyword in C#4 was not meant to be used in the below scenario. Use VS2010 code completion instead.


We know that if you are using TDD, then you should write your test before you are implementing anything else, don’t we :-)
image
Figure: 1. Write a failing test (red), 2. Make the test pass (green), 3. Refactor your code

But if you are thinking about new methods, you can’t really run the tests because your unit test wont compile, see the following example.

 

[TestMethod()]
        public void CalculatorThingAdd_2PositiveNumbers_ResultAdded()
        {
            // Arrange
            CalculatorThing myCalculator = new CalculatorThing();
            int result = 0; 
            int expcected = 3;

            // Act
            result = myCalculator.Addition(1, 2);
            
            // Assert
            Assert.AreEqual(result, expcected);

        }

ap--delete BAD code example: In TDD I would like to run this test, before I implement the method “Addition”

 

On compiling this test, you get the following error message

Error    1    'ConsoleApplication.CalculatorThing' does not contain a definition for 'Addition' and no extension method 'Addition' accepting a first argument of type 'ConsoleApplication.CalculatorThing' could be found (are you missing a using directive or an assembly reference?)   

 image
ap--delete Figure: Code want compile, because “Addition” is not implemented, and C# is static type safe on compile time

 

But you can avoid this by using the dynamic keyword, see below

 

 

[TestMethod()]
        public void CalculatorThingAdd_2PositiveNumbers_ResultAdded()
        {
            // Arrange
            dynamic myCalculator = new CalculatorThing();
            int result = 0; 
            int expcected = 3;

            // Act
            result = myCalculator.Addition(1, 2);
            
            // Assert
            Assert.AreEqual(result, expcected);

        }

apcheck_thumb1 GOOD code example: This code compiles nicely

 

 

image
apcheck_thumb1 Figure: Code compiles, because myCalculator is a dynamic object and evaluated on runtime not on compile time

 

But if you run this test you get:

image
Figure: Test failed because method not implement

Test method CalculatorConsole.Tests.CalculatorTest.CalculatorThingAdd_2PositiveNumbers_ResultAdded threw exception:
Microsoft.CSharp.RuntimeBinder.RuntimeBinderException: 'ConsoleApplication.CalculatorThing' does not contain a definition for 'Addition'

 

NICE!!!!
We have a failing test! 
image

Now go and implement the method and make the test pass!
image

Smack down!! WatiN vs Selenium vs VS2010 Test Lab Manager

*Updated* 21 March 2011: Updated how "Coded UI tests" finds a control with info from Balagans Blog - How does “Coded UI test” finds a control? 

 

We need Web functionality tests!!! (and a lot of people are already doing them)
Reasons?

  1. Easier to find bugs
  2. No need for a lot of manual testing
  3. Maintainability of your code (THIS IS BIG!!)
    1. When we change something (Code, DB, scripts, HTML,...) we want to verify if our user stories working as expected
    2. We setup web tests for each user story that we have.
  4. We can use web tests in load tests or stress tests
  5. … lots more

Note from Wikipedia
Stress testing: Simulates increased load, more than expected
Load testing: End to end performance testing under anticipated load

 

I tried the following 3 players (recommendations from work mates, and others..)

  1. Selenium
  2. WatiN
  3. Visual Studio 2010 & the Test & Lab Manager

All of these 3 tools provide a recording tool, where you can record your browsing actions and generate code from that.
This is important!!!
No one wants to write these tests manually!

 

Do the test recording

apcheck_thumb1 Selenium Test recorder just works.

Record your session. Copy & paste to Visual Studio. Done

ap--delete Watin Test recorder v2 throw exception

Bug reported here: http://sourceforge.net/tracker/index.php?func=detail&aid=2934193&group_id=193118&atid=944137

ap--delete Watin Test recorder V1 generates unsupported code -> manual fixing needed :-(

 

Code output of recorder

selenium.Open("/Public/default.aspx"); selenium.Click("//div[@id='userlogin']/div/div[2]"); selenium.Click("//div[@id='userstatusLoggedOut']/div/a/span"); selenium.WaitForPageToLoad("30000");
selenium.Type("ctl10_MainContentArea_ctl00_ctl00_CreateUserForm_CreateUserStepContainer_FirstName", "o"); selenium.Type("ctl10_MainContentArea_ctl00_ctl00_CreateUserForm_CreateUserStepContainer_LastName", "g"); selenium.Type("ctl10_MainContentArea_ctl00_ctl00_CreateUserForm_CreateUserStepContainer_Email", "peter@gfader.com"); selenium.Type("ctl10_MainContentArea_ctl00_ctl00_CreateUserForm_CreateUserStepContainer_ConfirmEmail", "peter@gfader.com"); selenium.Type("ctl10_MainContentArea_ctl00_ctl00_CreateUserForm_CreateUserStepContainer_Password", "password!"); selenium.Type("ctl10_MainContentArea_ctl00_ctl00_CreateUserForm_CreateUserStepContainer_ConfirmPassword", "password!"); selenium.Click("ctl10_MainContentArea_ctl00_ctl00_CreateUserForm___CustomNav0_StepNextButtonButton"); selenium.WaitForPageToLoad("30000");
selenium.Click("link=Log Out"); selenium.WaitForPageToLoad("30000");

Figure: Simulating a user registration with Selenium

 

IE ie = new IE("about:blank"); ie.GoTo("http://REMOVED.ssw.com.au/Public"); ie.Div(Find.ByCustom("innertext", "Member Login")).Click(); ie.Link(Find.ByUrl("http://REMOVED.ssw.com.au/Public/Profile/Register.aspx")).Click();
ie.TextField(Find.ByName("ctl10$MainContentArea$ctl00$ctl00$CreateUserForm$CreateUserStepContainer$FirstName")).TypeText("Peter"); ie.TextField(Find.ByName("ctl10$MainContentArea$ctl00$ctl00$CreateUserForm$CreateUserStepContainer$LastName")).TypeText("Gfader"); ie.TextField(Find.ByName("ctl10$MainContentArea$ctl00$ctl00$CreateUserForm$CreateUserStepContainer$Email")).TypeText("petermenuqggfader.com"); ie.TextField(Find.ByName("ctl10$MainContentArea$ctl00$ctl00$CreateUserForm$CreateUserStepContainer$Password")).TypeText("petermenuqggfader.com"); ie.TextField(Find.ByName("ctl10$MainContentArea$ctl00$ctl00$CreateUserForm$CreateUserStepContainer$Password")).TypeText("passmenumenuqword!"); ie.TextField(Find.ByName("ctl10$MainContentArea$ctl00$ctl00$CreateUserForm$CreateUserStepContainer$ConfirmPassword")).TypeText("passmenuqword!"); ie.Button(Find.ByName("ctl10$MainContentArea$ctl00$ctl00$CreateUserForm$__CustomNav0$StepNextButtonButton")).Click();

Figure: Simulating a user registration with WatiN

 

apcheck_thumb1 Selenium is a tool to create tests for web apps

apcheck_thumb1 Selenium’s output is a whole test class

apcheck_thumb1 Selenium’s output code is using relative URL’s (that you define in your test base URL)

apcheck_thumb1 Selenium code: Easy to read

ap--delete WatiN: The code output from the test recorder v1 is quite complicated to read.

I prefer Seleniums: “selenium.Click” instead of the long string and then seeing the “Click()”

// WatiN
watin.TextField(Find.ByName("ctl10$MainContentArea$ctl00$ctl00$CreateUserForm$CreateUserStepContainer$ConfirmPassword")).TypeText("password, f17");
watin.Button(Find.ByName("ctl10$MainContentArea$ctl00$ctl00$CreateUserForm$__CustomNav0$StepNextButtonButton")).Click();

// Selenium
selenium.Type("ctl10_MainContentArea_ctl00_ctl00_CreateUserForm_CreateUserStepContainer_ConfirmPassword", "password");
selenium.Click("ctl10_MainContentArea_ctl00_ctl00_CreateUserForm___CustomNav0_StepNextButtonButton");
         

Figure: Code comparison of WatiN with Selenium. Enter text in a password field and click on button

ap--delete WatiN : Output code from Watin Test recorder v1 was wrong.

Some input control TypeText() was missing
Finding of elements didn't always work E.g.  <a href="xx"> <span> My funkty test </span> </a>  

 

Running the tests

ap--delete Selenium needs a JAVA server to execute the tests

apcheck_thumb1 WatiN doesn't need a proxy server!

ap--delete Selenium is quite slow to run

Output from the Selenium Java server (see the 2 seconds of start up gap)

19:11:54.341 INFO - Command request: getNewBrowserSession[*chrome, http://REMOVED.ssw.com.au/Public/, ] on session null
19:11:54.341 INFO - creating new remote session
19:11:54.341 INFO - Allocated session 69581bdd207a4684b61f6c368af906f0 for http://REMOVED.ssw.com.au/Public/, launching...
19:11:54.370 INFO - Preparing Firefox profile...
19:11:56.895 INFO - Launching Firefox...

 

Code maintainance

apcheck_thumb1 Selenium makes working with Firefox perfectly together: uses the same name as in HTML

E.g. ctl10_MainContentArea_ctl00_ctl00_SubTotal

That means you can copy & paste from FireBug directly to Visual Studio

string priceSubTotalOnCheckout = selenium.GetText("ctl10_MainContentArea_ctl00_ctl00_SubTotal");

ap--delete Watin replaces the underscores with a dollar sign (This is annoying when copy paste from FireBug)

ctl10_MainContentArea_ctl00_ctl00_SubTotal
    needs to be converted to
ctl10$MainContentArea$ctl00$ctl00$SubTotal

string resultText = browser.Element(Find.ByName("ctl10$MainContentArea$ctl00$ctl00$SubTotal")).Text;

 

Note
image
Figure: Selenium is coming from the Java world, as you can see this here. No properties :-) --> GetXXX

 

What about  Visual Studio 2010 and Test & Lab Manager

  1. In Test & Lab Manager you define a test case that links to a user story
    1. User story: As a customer I want to search and buy a bag so that I satisfy my needs for a bag
    2. Test case below
      image
  2. Now you run you test with an Action recording
    1. This is easy. Just follow the instructions from the test case
    2. Done
  3. Close down Test Lab Manager and open Visual Studio, add "Coded UI test" with an "Existing action recording"
  4. Code that you get

[DataSource("Microsoft.VisualStudio.TestTools.DataSource.TestCase", "http://win-peterG:8080/tfs/DefaultCollection;Peter-Gfader-WebTest", "140", DataAccessMethod.Sequential), TestMethod] public void CodedUITestMethod1() { this.UIMap.Openbrowser(); this.UIMap.Gotostartpage();
this.UIMap.ClickonRegisterNew(); this.UIMap.EnterdetailsfirstnamelastnameemailpasswordParams.Ctl10MainContentAreaEditText = TestContext.DataRow["firstname"].ToString(); this.UIMap.EnterdetailsfirstnamelastnameemailpasswordParams.Ctl10MainContentAreaEdit1Text = TestContext.DataRow["lastname"].ToString(); this.UIMap.EnterdetailsfirstnamelastnameemailpasswordParams.Ctl10MainContentAreaEdit2Text1 = TestContext.DataRow["email"].ToString(); this.UIMap.EnterdetailsfirstnamelastnameemailpasswordParams.Ctl10MainContentAreaEdit3Text1 = TestContext.DataRow["email"].ToString(); this.UIMap.EnterdetailsfirstnamelastnameemailpasswordParams.Ctl10MainContentAreaEdit4Text = TestContext.DataRow["password"].ToString(); this.UIMap.EnterdetailsfirstnamelastnameemailpasswordParams.Ctl10MainContentAreaEdit5Text = TestContext.DataRow["password"].ToString(); this.UIMap.Enterdetailsfirstnamelastnameemailpassword(); this.UIMap.ClickonRegister();
this.UIMap.Searchforbag(); this.UIMap.Add1stbagfoundtoshoppingcart();
this.UIMap.Gotoshoppingcart();
this.UIMap.DoCheckout();
this.UIMap.EnterAddressdetails(); this.UIMap.Placeorder(); }

Figure: Code generated by VS2010 for a registration of a new user, searching for a bag, adding this bad and going through the checkout

apcheck_thumb1 VS2010 code is very easy to read. And there are a lot of things happening behind the scenes

UIMap is a huge file generated for you that does all the magic behind the scenes, like finding controls, clicking buttons, …

UIMap: Strongly typed representation of controls

 

How is Visual Studio finding controls?

        public HtmlInputButton RegisterButton
        {
            get
            {
                if ((this.mRegisterButton == null))
                {
                    this.mRegisterButton = new HtmlInputButton(this);

                    #region Search Criteria

                    this.mRegisterButton.SearchProperties[HtmlProperties.Button.Id] = "ctl10_MainContentArea_ctl00_ctl00_CreateUserForm___CustomNav0_StepNextButtonButton";
                    this.mRegisterButton.SearchProperties[HtmlProperties.Button.Name] = "ctl10$MainContentArea$ctl00$ctl00$CreateUserForm$__CustomNav0$StepNextButtonButton";
                    this.mRegisterButton.FilterProperties[HtmlProperties.Button.DisplayText] = "Register";
                    this.mRegisterButton.FilterProperties[HtmlProperties.Button.Type] = "submit";
                    this.mRegisterButton.FilterProperties[HtmlProperties.Button.Title] = null;
                    this.mRegisterButton.FilterProperties[HtmlProperties.Button.Class] = null;
                    this.mRegisterButton.FilterProperties[HtmlProperties.Button.ControlDefinition] = "id=ctl10_MainContentArea_ctl00_ctl00_Cre";
                    this.mRegisterButton.FilterProperties[HtmlProperties.Button.TagInstance] = "40";
                    this.mRegisterButton.WindowTitles.Add("Peter Gfader | Sign Up - Windows Internet Explorer");

                    #endregion

                }
                return this.mRegisterButton;
            }
        }

Figure: VS 2010 Beta2 generated code for finding a button on a web page. I think this is way TOO STRICT

ap--delete VS2010: All the "SearchProperties"above have to match, otherwise the button won’t be found. If too many controls are found from the "SearchProperties", the "FilterProperties" are applied one by one. All details on Balagans Blog - How does “Coded UI test” finds a control?

ap--delete There is no option to customize the default generated SearchProperties

 

I would probably change that to

        public HtmlInputButton RegisterButton
        {
            get
            {
                if ((this.mRegisterButton == null))
                {
                    this.mRegisterButton = new HtmlInputButton(this);
                    #region Search Criteria

                    this.mRegisterButton.FilterProperties[HtmlProperties.Button.DisplayText] = "Register";
                    this.mRegisterButton.FilterProperties[HtmlProperties.Button.Type] = "submit";

                    #endregion
                }
                return this.mRegisterButton;
            }
        }

apcheck_thumb1 Better way to search for the Register button. Filter on DisplayText and type of the control.
Note: This would fail if there are 2 buttons with "Register" and of type "Submit" on the page. Which is excellent!

 

Can VS2010 simulate a FireFox?
See this image for details about the VS2010 platform support
image
Figure: VS2010 platform support from http://videos.visitmix.com/MIX09/T83M

 

 WebAII looks very promising. I will definitely have a closer look on that tool in the next weeks, months…

 

Conclusion: Please count the apcheck_thumb1 green ticks and  ap--delete red crosses

Other interesting opinions about Watin and Selenium on testdrivendeveloper

 

PERSONAL
I would not automate the UI too much because that makes your test very fragile for future changes. That you will have sooner or later!

ap--delete BAD EXAMPLE
Create a coded UI test for a whole user interaction with your web app 
e.g. Register, Login, Browse, Find, Add to Shopping cart, Update Billing Address, Update Shipping Address, Checkout, Pay, See Order successful

Makes your UI test very fragile!
But could be a “Done” criteria for your SCRUM team: "An acceptance UI test must be written for each user story"

 

apcheck_thumb1 GOOD EXAMPLE
1. Create a coded UI tests for single screens
e.g. Logon screen:
  Assert "Username", "Password" boxes and "Login" button are there

2. Create a functional test for testing the actual Login functionality.

Latest Posts

Popular Posts