Thursday, September 24, 2009

WPF Styles and Animations

I have been working with WPF lately and I’m really impressed with the style capabilities. From a high level our goal when using styles is to be able to set some standard properties of various controls one time in one place and have them affect many or all of the controls of that type in our window or application.

Let’s start with a really basic window and a hand type a few controls.



Code Snippet



  1. <Window x:Class="Lesson1Styles.Window1"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. Title="Window1" Height="300" Width="300">
  5. <Grid>
  6. <Label Margin="0,25,0,0" VerticalAlignment="Top" >
  7. Style Driven Label
  8. </Label>
  9. <TextBox Margin="0,100,0,0" VerticalAlignment="Top">
  10. Style Driven TextBox
  11. </TextBox>
  12. <Button Margin="0,175,0,0" VerticalAlignment="Top" >
  13. Style Driven Button
  14. </Button>
  15. </Grid>
  16. </Window>




One of the reasons for hand typing the controls is that I chose to only set the margin and alignment of the controls and I didn’t want the designer to add any height and width properties. If we run the application now here is what we see.

image

Now let’s create a style for each of our controls by adding a Window.Resources element.



Code Snippet



  1. <Window.Resources>
  2. <Style TargetType="TextBox">
  3. <Setter Property="Background" Value="Yellow"/>
  4. <Setter Property="Foreground" Value="Purple"/>
  5. <Setter Property="BorderBrush" Value="Purple"/>
  6. <Setter Property="Width" Value="135"/>
  7. <Setter Property="Height" Value="30"/>
  8. </Style>
  9. <Style TargetType="Label">
  10. <Setter Property="Foreground" Value="Purple"/>
  11. <Setter Property="Background" Value="Yellow"/>
  12. <Setter Property="Width" Value="135"/>
  13. <Setter Property="Height" Value="33"/>
  14. </Style>
  15. <Style TargetType="Button">
  16. <Setter Property="Background" Value="Yellow"/>
  17. <Setter Property="Foreground" Value="Purple"/>
  18. <Setter Property="Width" Value="135"/>
  19. <Setter Property="Height" Value="30"/>
  20. </Style>
  21. </Window.Resources>




Our new window now looks like this:

image

Note - I did not have to set a style property on any of the UI Elements. This is because I set the TargetType property in each style and the runtime knew to apply each style to their corresponding controls. Any label, button, or textbox you add to the window will inherit these styles unless you explicitly override the style or individual properties of the style.

It would be highly unusual (ok…ugly) for us to want our labels, buttons, and textboxes to have the same size and color scheme but if we did, it would be nice to not have to duplicate these attributes for each control.

With style inheritance we can do just that. We declare a base style with a TargetType of Control and move all of the common properties into this style. The following refactored code will render the window exactly as we see above.



Code Snippet



  1. <Window.Resources>
  2. <Style x:Key="baseStyle" TargetType="Control">
  3. <Setter Property="Background" Value="Yellow"/>
  4. <Setter Property="Foreground" Value="Purple"/>
  5. <Setter Property="BorderBrush" Value="Purple"/>
  6. <Setter Property="Width" Value="135"/>
  7. <Setter Property="Height" Value="30"/>
  8. </Style>
  9. <Style TargetType="TextBox" BasedOn="{StaticResource baseStyle}">
  10. </Style>
  11. <Style TargetType="Label" BasedOn="{StaticResource baseStyle}">
  12. </Style>
  13. <Style TargetType="Button" BasedOn="{StaticResource baseStyle}">
  14. </Style>
  15. </Window.Resources>




Let’s look at how we can override a portion of the style. If we want our textbox style to have a different height and width than the base style we can simply duplicate the height and width property setter in the style for the textbox and set the value to whatever we want. For example, if we change the textbox style as follows:



Code Snippet



  1. <Style TargetType="TextBox" BasedOn="{StaticResource baseStyle}">
  2. <Setter Property="Width" Value="60"/>
  3. <Setter Property="Height" Value="60"/>
  4. </Style>




Our window looks like this:

image

We can even override these properties at the control level. Let’s add a Height property to our textbox control.



Code Snippet



  1. <TextBox Margin="0,100,0,0" VerticalAlignment="Top" Width="200">
  2. Style Driven TextBox
  3. </TextBox>




Now when we run, the textbox width is based on the property we set in the control – we override the style defined for the Button which in turn overrides the style we have set for all Controls.

image

To close things out let’s take a look at adding triggers to a style. If we want all labels to change their background color when the mouse is over the label we can add a Dependency Property Trigger to the style.



Code Snippet



  1. <Style TargetType="Label" BasedOn="{StaticResource baseStyle}">
  2. <Style.Triggers>
  3. <Trigger Property="IsMouseOver" Value="True">
  4. <Setter Property="Background" Value="Gray"/>
  5. </Trigger>
  6. </Style.Triggers>
  7. </Style>




If we want to animate the textbox when the mouse is over the control we can add a Dependency Property Trigger with a StoryBoard and Animation defined. This animation changes the Font Size, height, width, and background color of the textbox.



Code Snippet



  1. <Style TargetType="TextBox" BasedOn="{StaticResource baseStyle}">
  2. <Setter Property="Width" Value="60"/>
  3. <Setter Property="Height" Value="60"/>
  4. <Style.Triggers>
  5. <Trigger Property="IsMouseOver" Value="True">
  6. <Trigger.EnterActions>
  7. <BeginStoryboard Name="story1">
  8. <Storyboard Duration="0:0:5">
  9. <DoubleAnimation Storyboard.TargetProperty="FontSize" To="20"/>
  10. <ColorAnimation Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)" To="Gray"/>
  11. <DoubleAnimation Storyboard.TargetProperty="Height" To="50"/>
  12. <DoubleAnimation Storyboard.TargetProperty="Width" To="270"/>
  13. </Storyboard>
  14. </BeginStoryboard>
  15. </Trigger.EnterActions>
  16. <Trigger.ExitActions>
  17. <StopStoryboard BeginStoryboardName="story1"/>
  18. </Trigger.ExitActions>
  19. </Trigger>
  20. </Style.Triggers>
  21. </Style>




Finally we’ll add a Routed Event trigger to the button just to demonstrate the different trigger options.



Code Snippet



  1. <Style TargetType="Button" BasedOn="{StaticResource baseStyle}">
  2. <Style.Triggers>
  3. <EventTrigger RoutedEvent="Mouse.MouseEnter" >
  4. <BeginStoryboard Name="story3">
  5. <Storyboard Duration="0:0:2">
  6. <DoubleAnimation
  7. Duration="0:0:0.2"
  8. Storyboard.TargetProperty="Height"
  9. To="90" />
  10. </Storyboard>
  11. </BeginStoryboard>
  12. </EventTrigger>
  13. <EventTrigger RoutedEvent="Mouse.MouseLeave" >
  14. <BeginStoryboard Name="story34">
  15. <Storyboard Duration="0:0:2">
  16. <DoubleAnimation
  17. Duration="0:0:0.2"
  18. Storyboard.TargetProperty="Height" />
  19. </Storyboard>
  20. </BeginStoryboard>
  21. </EventTrigger>
  22. </Style.Triggers>
  23. </Style>




We could do all of the styling and animation in code if we want but the good thing about doing this declaratively is if we are not happy with our Minnesota Viking look and feel, we can have a UI designer use a tool like Expression Blend to make things look nice without requiring that they understand code or XAML.

Try adding some other textboxes, labels, and buttons to see what style properties are inherited.

Here is the XAML in it’s entirety:



Code Snippet



  1. <Window x:Class="Lesson1Styles.Window1"
  2. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  3. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  4. Title="Window1" Height="300" Width="300">
  5. <Window.Resources>
  6. <Style x:Key="baseStyle" TargetType="Control">
  7. <Setter Property="Background" Value="Yellow"/>
  8. <Setter Property="Foreground" Value="Purple"/>
  9. <Setter Property="BorderBrush" Value="Purple"/>
  10. <Setter Property="Width" Value="135"/>
  11. <Setter Property="Height" Value="30"/>
  12. </Style>
  13. <Style TargetType="TextBox" BasedOn="{StaticResource baseStyle}">
  14. <Setter Property="Width" Value="60"/>
  15. <Setter Property="Height" Value="60"/>
  16. <Style.Triggers>
  17. <Trigger Property="IsMouseOver" Value="True">
  18. <Trigger.EnterActions>
  19. <BeginStoryboard Name="story1">
  20. <Storyboard Duration="0:0:5">
  21. <DoubleAnimation Storyboard.TargetProperty="FontSize" To="20"/>
  22. <ColorAnimation Storyboard.TargetProperty="(Background).(SolidColorBrush.Color)" To="Gray"/>
  23. <DoubleAnimation Storyboard.TargetProperty="Height" To="50"/>
  24. <DoubleAnimation Storyboard.TargetProperty="Width" To="270"/>
  25. </Storyboard>
  26. </BeginStoryboard>
  27. </Trigger.EnterActions>
  28. <Trigger.ExitActions>
  29. <StopStoryboard BeginStoryboardName="story1"/>
  30. </Trigger.ExitActions>
  31. </Trigger>
  32. </Style.Triggers>
  33. </Style>
  34. <Style TargetType="Label" BasedOn="{StaticResource baseStyle}">
  35. <Style.Triggers>
  36. <Trigger Property="IsMouseOver" Value="True">
  37. <Setter Property="Background" Value="Gray"/>
  38. </Trigger>
  39. </Style.Triggers>
  40. </Style>
  41. <Style TargetType="Button" BasedOn="{StaticResource baseStyle}">
  42. <Style.Triggers>
  43. <EventTrigger RoutedEvent="Mouse.MouseEnter" >
  44. <BeginStoryboard Name="story3">
  45. <Storyboard Duration="0:0:2">
  46. <DoubleAnimation
  47. Duration="0:0:0.2"
  48. Storyboard.TargetProperty="Height"
  49. To="90" />
  50. </Storyboard>
  51. </BeginStoryboard>
  52. </EventTrigger>
  53. <EventTrigger RoutedEvent="Mouse.MouseLeave" >
  54. <BeginStoryboard Name="story34">
  55. <Storyboard Duration="0:0:2">
  56. <DoubleAnimation
  57. Duration="0:0:0.2"
  58. Storyboard.TargetProperty="Height" />
  59. </Storyboard>
  60. </BeginStoryboard>
  61. </EventTrigger>
  62. </Style.Triggers>
  63. </Style>
  64. </Window.Resources>
  65. <Grid>
  66. <Label Margin="0,25,0,0" VerticalAlignment="Top" >
  67. Style Driven Label
  68. </Label>
  69. <TextBox Margin="0,100,0,0" VerticalAlignment="Top" Width="200">
  70. Style Driven TextBox
  71. </TextBox>
  72. <Button Margin="0,175,0,0" VerticalAlignment="Top" >
  73. Style Driven Button
  74. </Button>
  75. </Grid>
  76. </Window>




Saturday, September 19, 2009

VSTS 2010 Test Run recording

In part four of my series on using Microsoft Test and Lab Manager we are going to take a look at test runner.

Here is the recording I showed at the VSTS MN user group.  By way of setting things up I am executing a single manual test that results in a failure in our expected result.  It is the first time I ran (and recorded) the test so when test runner comes up I do not have the option of executing the recorded test.  Here is a screen grab of what it would look like if I had the recording in place:

image

Of special note is the very powerful Start test and play option.  This will allow you to execute each step via the recording (no room for mistakes) and enter the results as each step is finished.

In my video I run through creating a bug and then click through what things were attached to the bug based on my run settings. 

Microsoft Test and Lab Manager. Test planning and execution.

I was the presenter at the Minnesota VSTS Users Group this week.  The topics I discussed included; test planning and execution with Microsoft Test and Lab Manager, test impact analysis, coded UI testing, and historical debugger.  You can get a PDF version of my slide deck here.  I had a couple presentation gremlins when I was introducing the historical debugger so I added a couple new slides explaining the configuration necessary to get the behavior I was describing during the presentation.

The slides themselves will do little more than wet your appetite so I’ll do a series of posts and add some narration describing what we are seeing and how it fits into the QA process.

Part 1, Getting organized.

Part 2, Test planning

Part 3, Executing manual tests

Part 4, the test run.

Part 5, Test impact analysis.

I’ll cover the Coded UI test and Historical debugger elsewhere.

A look at test planning with Microsoft Test and Lab Manager. Part 1, getting organized

Let’s start with a high level look at the Test and Lab Manager.  Test and Lab Manager is broken into 3 different areas; Lab Center, Test Center, and Organize.  I’m not going to go into the lab center, I’m primarily going to look at the area of the product that a QA professional would use on a day to day basis. 

The Lab Center:

image

This is where you manage environments, test run settings, environment templates and test controllers. We’ll drill into a couple of these concepts later.

The Organize area:

Test Plan tab.

image

The Test Plan tab of the organize area is where you manage test plan definitions and their context. This page contains a list of all plans associated with a TFS project.

Configuration tab.

image

The configuration tab is used to manage the different configurations you want to use during testing.  In our example we have defined 4 configurations;

  • Vista with .Net framework 3.5
  • Vista with .Net framework 4.0
  • Vista with the Firefox browser
  • Vista with IE 7

The configuration variables are just name value pairs which may be managed by drilling into this tab.

Test Cases tab

image

Test Cases may be created copied and edited here.  This is a place QA can go to create test cases rather than using team explorer and visual studio.  The list is all test cases associated to the configured team project.  Note: the context at the top center of the screen is a link that may be used to change your team project.

Shared Steps tab:

image

The idea of a shared step is that you may define commonly executed testing steps in this one place (login for example). When defining other tests that include these common steps, you may reference this shared step rather than duplicating the steps necessary to perform the common task. Not only is it less work to create tests when you use shared steps (less typing) but maintaining this common logic is much simpler as a change to the common task only needs to be made in the shared step – not in every test that calls it.   

The shared steps tab is the place you would go to create, edit, copy, and record a shared step.  Like test plans and test cases, the list is all shared steps associated to a team project. 

In future posts I’ll go into more detail about creating the plans and tests as well as cover executing the test plans.

Tuesday, September 8, 2009

Design and Code Review Checklist

I have been blogging about some of the principles I use in design/code reviews reviews.  Here is the full list of topics I look for, I’ll create links as I blog about more individual items in the future.

  • Review Unit Tests
  • Is the code in the right place?
  • Does the name space make sense? http://blogs.msdn.com/brada/articles/361363.aspx
  • Is the class / procedure / variable scope correct.
  • Are the Classes, methods, and variables named correctly? http://blogs.msdn.com/brada/articles/361363.aspx
  • Are the methods, and variables typed correctly?
  • Look at the code.
  • Review for OCP  (open closed principle - Open for extension closed for modification)
  • Review for DRY Principle (Don't Repeat Yourself - abstract common things and put in single place).
  • Review for SRP (Single Responsibility Principle - every object has a single responsibility. All the object's services should be focused on that responsibility).
  • Review for LSP (Liskov Substitution Principle Subtypes must be substitutable for their base types).
  • Consider delegation over inheritance. If you don't need to change base class behavior, consider delegating (handing over responsibility of a task) rather than inheritance.
  • Consider Composition over inheritance. Similar to delegation except the owner class uses a set of behaviors and chooses which one to use at runtime. When the delegating class is destroyed, so are all the child classes.
  • Aggregation. Similar to composition except when the delegating class is destroyed, the child classes are not.
  • Consider Polymorphism. Make a group of heterogeneous classes look homogeneous
  • Consider generics.
  • Testability considerations?
  • YAGNI (You aint gonna need it) When in doubt, leave it out!
  • Does object wake up in a known good state (constructor)
  • Consider Security.

 

Saturday, September 5, 2009

Design Review – Liskov Substitution Principle

The (Barbara) Liskov Substitution principle states:

If for each object o1 of type S there is an object o2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o1 is substituted for o2 then S is a subtype of T.

That hurts my head.  Let’s again go with the definition from “Agile Principles, Patterns, And Practices in C#” Robert C Martin and Micah Martin:  Subtypes must be substitutable for their base type.

There are two angles from which I want to look at this principle. Let’s look at it first from a structural standpoint.  I’m going to reuse the refactored code from my last post with a slight change.  Rather than having the conditions and actions implement the ISupportRules interface, they will be derived from an abstract class named RuleBase. This means our RulesEngine’s ExecuteRules method needs to accept a generic list of RuleBase.

The Code:

We have our enums :



Code Snippet



  1. namespace OpenClosePrinciple
  2. {
  3.     public enum Actions
  4.     {
  5.         CreateOrder,
  6.         CreateBackorder,
  7.         CloseOrder,
  8.         ShipOrder,
  9.         StoreOrder,
  10.         ReduceInventory
  11.     }
  12.     public enum Conditions
  13.     {
  14.         IsComplete,
  15.         IsInStock,
  16.         CanShip
  17.     }
  18.     public enum RuleType
  19.     {
  20.         Condition,
  21.         Action
  22.     }
  23. }




An Action derived from RuleBase:



Code Snippet



  1. namespace OpenClosePrinciple
  2. {
  3.     public class CreateOrderAction:RuleBase
  4.     {
  5.         #region ISupportRules Members
  6.         public override bool Execute()
  7.         {
  8.             return true;
  9.         }
  10.         public override RuleType TypeOfRule()
  11.         {
  12.             return RuleType.Action;
  13.         }
  14.         #endregion
  15.     }
  16. }




A Condition derived from RuleBase:



Code Snippet



  1. namespace OpenClosePrinciple
  2. {
  3.     public class CanShipCondition:RuleBase
  4.     {
  5.         #region ISupportRules Members
  6.         public override bool Execute()
  7.         {
  8.             return true;
  9.         }
  10.         public override RuleType TypeOfRule()
  11.         {
  12.             return RuleType.Condition;
  13.         }
  14.         #endregion
  15.     }
  16. }




RuleBase:



Code Snippet



  1. namespace OpenClosePrinciple
  2. {
  3.     public abstract class RuleBase
  4.     {
  5.         public virtual bool Execute()
  6.         {
  7.             return true;
  8.         }
  9.         public abstract RuleType TypeOfRule();
  10.     }
  11. }




The Rule Engine.



Code Snippet



  1. using System;
  2. using System.Data.SqlClient;
  3. using System.Collections.Generic;
  4. namespace OpenClosePrinciple
  5. {
  6.     public class RefactoredRuleEngine
  7.     {
  8.         public void ExecuteRules(List<RuleBase> rules)
  9.         {
  10.             bool executing = true;
  11.             int ruleIndex = 0;
  12.             while (executing)
  13.             {
  14.                 if (rules[ruleIndex].TypeOfRule() == RuleType.Action)
  15.                 {
  16.                     executing = rules[ruleIndex].Execute();
  17.                     ruleIndex++;
  18.                 }
  19.                 else
  20.                 {
  21.                     if (rules[ruleIndex].Execute())
  22.                     {
  23.                         ruleIndex++;
  24.                         executing = true;
  25.                     }
  26.                     else
  27.                     {
  28.                         ruleIndex += 2;
  29.                         executing = true;
  30.                     }
  31.                 }
  32.                 //Implement some exit strategy here
  33.             }
  34.         }
  35.     }
  36. }




 

Our Base class simply supports an Execute and a RuleType Method.  Both our condition and Action class derive from RuleBase and may be “passed around” as a RuleBase and therefore we have satisfied the structural idea of being able to substitute a derived class for it’s base class.

The second angle I want to look at this principle is from a behavioral perspective.  Most examples I read demonstrating an LSP violation use the Rectangle base class and the square subclass.   Proof of the LSP violation is based on setting the length and width of the Square to unique values then discovering that an assert in a unit test that calculates a rectangles area returns an incorrect result.  

I agree that this is a violation.  I believe the problem lies in the claim that a square “is-a” rectangle.  Now don’t go running to a dictionary and grab the definition of a rectangle and tell me that a square fits the definition of a rectangle – I’m not talking about the English language. 

The classic implementation of the rectangle when discussing the LSP principle is to expose a Width and a Height property and a CalculateArea method which returns Width X Height.  This makes sense.  The problem in claiming that the Square “is-a” Rectangle is that with a Square there is not a notion of a Width and a Height that are different.  The Width and Height must be the same.  It doesn’t make sense to expose 2 properties, it is misleading and a consumer can logically assume that they would be independent properties.  But in the implementation of the square this is not the case.  Our Square is not (logically) a Rectangle because it does not have a Length and Width that are independent of each other.

To consider whether our design above has violated LSP from a behavior standpoint we have to take a look at the RuleEngine.  At a glance it looks like we have a violation, notice that we have some logic in the engine that concerns itself with the RuleType.

if (rules[ruleIndex].TypeOfRule() == RuleType.Action) …

This does have the “smell” of bad code that we need to constantly look for but I maintain that if we take a closer look this is NOT a violation.  When we cooked up the notion of the RuleEngine we decided we would support 2 types of rules, Conditions and Actions.  It is reasonable to do this.  We would never get our code out the door if we didn’t put some constraints on the types of rules we could support.  The line of code in question is simply executing code based on whether it is a condition or an action.

An example of code that would violate LSP or OCP would be as follows:

if (TypeOf(rules[ruleIndex]) == CanShipCondition)

Here we are trying to execute logic based on the derived type which is a violation of OCP and LSP.  The consumer of the base class would not have to worry about the derived type if the derived type was substitutable for it’s base class and by worrying about derived types, the rules engine is no longer open for extension.

My design review checklist