RSS
 

Silverlight Unit Testing: Howto

12 Aug

This post will walk you through setting up a Unit Test Project for your Silverlight Application. It took me a day to successfully set everything up and make it working on a Team Foundation Build Server. The Silverlight Unit Test Framework is already out some years (starting from Silverlight 2) but with every new framework it is good to wait for some maturity. I will blog about the Unit Testing framework as it is now in Silverlight 4.

Prerequisites:

Setup your Unit Test Silverlight Application

After installing the Silverlight Toolkit, you should have a Silverlight Unit Test Project available. The following screens will walk you through the setup.

 

    

 

Unit Testing your XAML Bindings

As we all use MVVM in our Silverlight applications these days… Make sure it doesn’t break any of the bindings.

Reasons that I could think of to test your XAML bindings.

  • Typographical error in your XAML
  • Make sure you don’t miss the silent tracing error of your binding mistake
  • Your object property name changes
  • Designers might mess with your bindings

 

First approach (howto test XAML bindings??)

There is a post by Jeremy Likeness that deals with testing your XAML bindings. The post was quite good and you get the idea but the code didn’t work very well for me.

Second and working approach.

The following code works for me and has a completely different approach. Silverlight Unit Testing has a number of methods to support the behaviour we are trying to test.

        [Asynchronous]
        [TestMethod]
        [Tag("WorkflowDefinitionBindingIsValid")]
        public void WorkflowDefinitionBindingIsValid()
        {
            EnqueueDelay(10);

            // Internal Property Available using Assembly InternalsVisibleTo on Silverlight Project
            var cbBooksCombobox = _booksView.cbBooksCombobox;

            EnqueueCallback(() => { _booksViewModel.Books = _books; });
            EnqueueCallback(() => CollectionAssert.AreEquivalent(cbBooksCombobox.Items, _books,
                                                    "Failed to data-bind books."));

            EnqueueTestComplete();
        }

Explanation:

  • The Asynchronous Attribute is very important for these kind of tests. We want to allow the bindings to update before we continue further test execution.

 

  • Enqueue methods
    • EnqueueTestComplete() – This method indicates that your test is complete.
    • EnqueueCallback() – This method will add a callback to your test method.
    • EnqueueConditional() – Continue testing after the condition is met.
    • EnqueueDelay() – Add a delay before continuing to evaluate work items.
    • EnqueueWorkItem – This adds a task to the task queue.

 

  • Getting access to the internal properties of your viewModel
        [assembly: InternalsVisibleTo("org.vanderbiest.UnitTests")]

 

  • Tagging your tests

You can tag your class and also tag your methods. I find it handy to tag both so you can test individual methods or just test your entire fixture class.

As you can see in the Sample Screenshot, I have placed my own Favorite Tags in the list. To achieve that, you will add the following code to the App.xaml.cs Startup event.

        private void Application_Startup(object sender, StartupEventArgs e)
        {
            var settings = UnitTestSystem.CreateDefaultSettings();
            settings.SampleTags.Clear();
            settings.SampleTags.Add("BaseViewModelFixture");
            settings.SampleTags.Add("BookListViewModelFixture");
            settings.SampleTags.Add("MusicListViewModelFixture");
            RootVisual = UnitTestSystem.CreateTestPage(settings);
        }

 

Third approach: EnqueueConditional method

You might also want to check the following approach:

[TimeOut(200)]
[TestMethod]
[Asynchronous]
public void Test2()
{
int pageCount = 0;
FlickrRequest request = new FlickrRequest(typeof(MockTestableWebClient));
request.PhotoSearchByUser("97044050@N00", (photo) => pageCount++);
EnqueueConditional(() =>
{
return pageCount == 5;
});
EnqueueTestComplete();
}

This code will wait for a certain condition to be completed. Notice the TimeOut attribute to make sure you don’t fall into an endless loop…

The EnqueueCondition becomes handy when you want to test real time WCF calls.

Automating your Silveright Unit Tests at Build Server

StatLight

Differences in StatLight Visual Studio Debug - No Error Logging in TestInitialize

If something goes wrong in your Test Initialization you won’t get a good error description in StatLight. This is because of the Silverlight Test Framework not throwing any exceptions in your Test Initialization. Of course we don’t have any problems with it as long as we can debug our code but with StatLight, things are a bit different. It is recommended that you have a Smoke test that just checks your Initialization method for errors.

        [TestInitialize]
        public void TestInit()
        {
            // Nothing goes wrong here as we can see in our smoke test
        }

        [TestMethod]
        [Description("Tests the InitializeMethod")]
        [Tag("SmokeTest")]
        public void SmokeTest()
        {
            TestInit();
        }

Caveat?

Resources are not automatically recognized by Statlight. You need to add them manually. What resources you need to add manually can be discovered by using the smoke test. To add a resource manually, you need to add the following code:

        public static void Get()
        {
            Application.Current.Resources.MergedDictionaries.Add(new ResourceDictionary
            {
                Source =
                    new Uri(
                    "/org.vanderbiest.Shell;component/Assets/Styles/BaseStyle.xaml",
                    UriKind.RelativeOrAbsolute)
            });
        }

Testing UIElements requires the -b option.

When you run your Silverlight Unit Tests in Visual Studio, the browser will load the XAP file and launch all the tests. The default with StatLight is that it runs without a browser. Luckily for us we can test our XAML bindings using the -b option. Statlight has its own browser process window so that tests will run in a browser context.

 

Reporting using StatLight

StatLight.exe -x=MyTestXapFile.xap -b -ReportOutputFile=C:\temp\test.xml



  
    
      
        Description
      
    
    
   

Why? StatLight is a commandline utility that will execute your tests in an automated environment.
Reports.

Howto?

  • You can install StatLight as a NuGet Package.

 

 

Visual Studio Silverlight Unit Test Result Viewers

Usage? Instead of running in a browser window or launch a command line process, directly view your Unit Test Results in Visual Studio.

AgUnit

Installation

Download: AgUnit on CodePlex

Copy the extracted files from AgUnit-0.4-for-ReSharper-6.0.zip into the “Bin\Plugins\” folder of your ReSharper installation
(default C:\Program Files\JetBrains\ReSharper\v6.0\Bin\Plugins), create this folder if it does not exist. Delete any previous versions of AgUnit you may have in this folder.

Caveat

As you will see with XAML binding tests… Async is currently not working

 

Unit Test Result Viewer for StatLight

Download from Visual Studio Gallery

Overall, the plugin did not help me at all. I experienced the following problems:

  • Test Project should not be located in a Solution Folder (the assembly will not be recognized by the Result Viewer Tool)
  • I could not make it work (after placing StatLight in my Appdata/Local directory), I must did something wrong ;)

 

Conclusion

There are still some Caveats and there isn’t very much documentation on the net but you can make it work as I described in this blog post.

 

 

Listbox Individual Item Color in Silverlight

12 Jul

This post is mainly a reply on this StackOverflow Question: how to change listbox item’s color individually programmatically in silverlight?

We want to modify the Listbox item template so we get the following layout:

The implementation is fairly simple. We use a converter on our Listbox Item binding and return a Style Property.

The Message Model implementation:

public class Message
    {
        public string Name { get; set; }
        public bool IsInError { get { return String.IsNullOrEmpty(ErrorMessage); } }
        public string ErrorMessage { get; set; }
    }

In the listbox, we will bind these message properties for each item. We can have a different style based on these properties by using the listbox ItemTemplate.
The Listbox Item Template implementation:

        
            
                
                        
                
            
        

For each listbox item, we will assign a style for our TextBlock element.
The Converter implementation:

        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if ((bool)value)
            {
                return Application.Current.Resources["ListBoxTextNormalItem"];
            }

            return Application.Current.Resources["ListBoxTextErrorItem"];
        }

The Style implementation:

        

        

You can download the sample source here: ListBoxItemColorSample

 
 

Debugging Team Foundation Server 2010 Build Workflow

23 May

Lately, I had some time to spend on developing Workflows with the Windows Workflow Foundation v4.0. I need to make some modifications to our build workflow template.

Howto Debug Team Foundation 2010 Workflow

There is an excellent post on how to debug TFS 2010 Workflows:
http://blogs.microsoft.co.il/blogs/baruchf/archive/2009/07/02/debugging-team-build-now-you-can.aspx

Problem…

I had the following problem after performing the steps from his blog:
When your xaml workflow file has been created on a different machine, the path to debug will not work.

You can see this in the output (Debug) window of your visual studio after attaching to process (“TFSBuildServiceHost.exe”).

‘TFSBuildServiceHost.exe’ (Managed (v4.0.30319)): Loaded ‘Workflow’
Instrumentation for debugger fails. Reason: Could not find file ‘C:\tfs\project\build\myBuildTemplate.xaml’..’TFSBuildServiceHost.exe’ (Managed (v4.0.30319)): Loaded ‘Workflow’

You will notice the following breakpoints will never be hit:

Solution

Edit your Template XAML file in a text editor and change the following filename value.


    
    
 

Make sure you check-in your workflow template and your breakpoints will be hit:

Caveat?

However, there is a caveat when debugging the “Run On Agent” Activity. I haven’t found a way to debug the activity itself. Breakpoints outside the activity will be hit, breakpoints inside it will just be skipped. The same problem for scoped variables. Variables that are defined inside the Run On Agent activity are null when you use them outside the activity. Weird behaviour but I ended with moving my logic inside the Run On Agent after it was debugged properly with static variables.

 

Transformation Config File expects Namespace Manager or XsltContext

12 May

What was happening?

I’m using custom config transformations in order to have different configs for each Azure deployment. You can modify your WebRole project like Alex Lambert showed us.

When using MSBuild we define a target that uses XMLTransform.


    

    
        
    

What was the error?

ServiceDefinition.Staging.csdef(3,15): error : Namespace Manager or XsltContext needed. This query has a prefix, variable, or user-defined function.

When working with code, you probably know what to do… But what if you’re having this in a Transformations config file?

The problem is that an Xpath expression was not found correctly.

We can directly trigger our target using the Visual Studio Command Prompt: “msbuild yourProject.cssproj /t:YourTargetName” to test this transformation. This was just failing over and over again, it kept me busy for hours because I was looking at the wrong spot. The errors in visual studio were also telling me that the attribute xdt:Transform was not declared. Even if the namespace import is present… xmlns:xdt=”http://schemas.microsoft.com/XML-Document-Transform” but that’s something you might ignore…

Whenever you have this error using Config Transformations  make sure you have the correct elements in your original config file that you are trying to transform using your transformations file. If an element could not be found, it will throw this exception.

Example

ServiceDefinition.csdef



  
    
      
        
          
        
      
    
    
      
    
    
      
    
    
      
    
     

ServiceDefinition.Staging.csdef



  
    
      
      
    
  

Whenever you make a mistake in the Locator Xpath that gets the Match you will receive the error (as you can see in MyWrongWeb).

 

Automated Tests: test your database using SQL Server Snapshots

22 Nov

It makes sense to unit test your database to see if you can do CRUD operations especially when you’re working with LINQ2SQL or Entity Framework. After reading this article by Graeme Hill, we could work with the following methods.

  • Put each test in a transaction
    • Single session, possible deadlocks
  • Rebuild the database after each test
    • Slow
  • Use SQL Server snapshots
    • Looks nice, how to automate this?
  • Distributed Transactions
    • This is the recommended approach. However, our code we want to test is already using Distributed Transactions. Because we will have a transaction A inside another transaction B, we can’t use any foreign key references in transaction C and we’re unable to test all our methods. The transaction B will be committed but as this transaction resides in another transaction A the changes are not reflected to transaction C.

So if we go for the Server snapshot, the rest of this post describes how you can implemented it.

SQL Server snapshot implementation.

There are 3 stored procedures to make this work. You need to create the procedures on a different database than the one you are taking snapshots from (preferably master database).

Creating the snapshot

Needs 4 required parameters.

  • sqlDatabaseName: name of your database
  • sqlSnapShotPath: full path of your snapshot location on your disk (eg. c:\myfolder\)
  • sqlSnapShotName: the name of your snapshot
  • sqlInternalDatabaseName: the internal name of your database
USE [master]
GO
/****** Object:  StoredProcedure [dbo].[Test_CreateSnapShot]    Script Date: 11/21/2010 23:31:19 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[Test_CreateSnapShot]
	-- Add the parameters for the stored procedure here
	@sqlDatabaseName                   varchar(512),
	@sqlSnapShotPath               varchar(512),
	@sqlSnapShotName	               varchar(512),
	@sqlInternalDatabaseName		varchar(512)
AS
BEGIN
	-- SET NOCOUNT ON added to prevent extra result sets from
	-- interfering with SELECT statements.
	SET NOCOUNT ON;

    DECLARE @sql varchar(500)
  Select @sqlSnapShotPath = @sqlSnapShotPath + @sqlSnapShotName

Select @sql = 'CREATE DATABASE ' + @sqlSnapShotName + ' ON (NAME=' + @sqlInternalDatabaseName + ', FILENAME='''
+ @sqlSnapShotPath + ''') AS SNAPSHOT OF ' + @sqlDatabaseName
print @sql
EXEC(@sql)
END

Closing open connections

The procedure will check the database for any existing connections when replacing the snapshot. If you don’t kill any open connections, you will have the following error.

System.Data.SqlClient.SqlError: RESTORE cannot process database ‘DbName’ because it is in use by this session. It is recommended that the master database be used when performing this operation.

USE [master]
GO
/****** Object:  StoredProcedure [dbo].[Test_ClearDBUsers]    Script Date: 11/21/2010 23:44:29 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
  CREATE PROCEDURE [dbo].[Test_ClearDBUsers]
    @dbName SYSNAME
AS
BEGIN
    SET NOCOUNT ON 

    DECLARE @spid INT,
        @cnt INT,
        @sql VARCHAR(255) 

    SELECT @spid = MIN(spid), @cnt = COUNT(*)
        FROM master..sysprocesses
        WHERE dbid = DB_ID(@dbname)
        AND spid != @@SPID 

    PRINT 'Starting to KILL '+RTRIM(@cnt)+' processes.' 

    WHILE @spid IS NOT NULL
    BEGIN
        PRINT 'About to KILL '+RTRIM(@spid)
        SET @sql = 'KILL '+RTRIM(@spid)
        EXEC(@sql)
        SELECT @spid = MIN(spid), @cnt = COUNT(*)
            FROM master..sysprocesses
            WHERE dbid = DB_ID(@dbname)
            AND spid != @@SPID
        PRINT RTRIM(@cnt)+' processes remain.'
    END
END

Restoring the snapshot

This procedure uses the ClearDBUsers procedure.
Needs 2 required parameters.

  • sqlDatabaseName: name of your database
  • sqlSnapshotName: the name of your snapshot (same name you gave when creating the snapshot)
USE [master]
GO
/****** Object:  StoredProcedure [dbo].[Test_RestoreSnapShot]    Script Date: 11/21/2010 23:47:12 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[Test_RestoreSnapShot]
	-- Add the parameters for the stored procedure here
	@sqlDatabaseName                   varchar(512),
	@sqlSnapshotName	               varchar(512)
AS
BEGIN
	-- SET NOCOUNT ON added to prevent extra result sets from
	-- interfering with SELECT statements.
	SET NOCOUNT ON;

	DECLARE @sql varchar(500)

-- make sure we operate on the master and not on the database to restore
-- use master (sp will do this for us)
-- cloase any existing connections
execute Test_ClearDBUsers @sqlDatabaseName

-- restore!
RESTORE DATABASE @sqlDatabaseName
FROM DATABASE_SNAPSHOT = @sqlSnapshotName
Select @sql = 'DROP DATABASE ' + @sqlSnapshotName
exec(@sql)
END

When using Unit Testing, you can call the stored procedures on ClassInitialize (create the snapshot) and on ClassCleanup (remove the snapshot). Creating an ordered Unit Test will make sure we can create our objects first, update (with the right foreign key references) and delete them. How to: Create an ordered test.

        [ClassCleanup()]
        public static void AfterAllTests()
        {
            SqlTestSetup.DeleteSnapShot();
        }

        [ClassInitialize()]
        public static void MyClassInitialize(TestContext testContext)
        {
            SqlTestSetup.CreateSnapShot();
        }

Calling the stored procedure can be done using your preferred method. This is an example using the Microsoft Data Access Application Blocks.

public static class SqlTestSetup
	{
        private const string spCreateSnapShot = "cip_Test_CreateSnapShot";
        private const string spRestoreSnapShot = "cip_Test_RestoreSnapShot";

        private static string ConnectionString
        {
            get { return ConfigurationManager.ConnectionStrings["CipDatabase"].ConnectionString; }
        }

        public static void CreateSnapShot()
        {
            SqlConnection sqlConnection = new SqlConnection(ConnectionString);

            var paramDatabaseName = new SqlParameter() { ParameterName = "@sqlDatabaseName", SqlValue = SqlDbType.VarChar, Value = sqlConnection.Database.ToString() };
            var paramSnapShotPath = new SqlParameter() { ParameterName = "@sqlSnapShotPath", SqlValue = SqlDbType.VarChar, Value = ConfigurationManager.AppSettings["DBSnapShotPath"].ToString() };
            var paramSqlSnapShotName = new SqlParameter() { ParameterName = "@sqlSnapShotName", SqlValue = SqlDbType.VarChar, Value = ConfigurationManager.AppSettings["DBSnapShotName"].ToString() };
            var paramSqlInternalDatabasName = new SqlParameter() { ParameterName = "@sqlInternalDatabaseName", SqlValue = SqlDbType.VarChar, Value = ConfigurationManager.AppSettings["DBInternalName"].ToString() };

            var parameterValues = new SqlParameter[] { paramDatabaseName, paramSnapShotPath, paramSqlSnapShotName, paramSqlInternalDatabasName };

            // SP should be executed from master db
            string masterConnectionString = ConnectionString.Replace(sqlConnection.Database.ToString(), "master");

            SqlHelper.ExecuteDataset(new SqlConnection(masterConnectionString), CommandType.StoredProcedure,
                                                                     spCreateSnapShot, parameterValues);

        }

        public static void DeleteSnapShot()
        {

            SqlConnection sqlConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["CipDatabase"].ConnectionString);

            var paramDatabaseName = new SqlParameter() { ParameterName = "@sqlDatabaseName", SqlValue = SqlDbType.VarChar, Value = sqlConnection.Database.ToString() };
            var paramSnapShotPath = new SqlParameter() { ParameterName = "@sqlSnapShotName", SqlValue = SqlDbType.VarChar, Value = ConfigurationManager.AppSettings["DBSnapShotName"].ToString() };

            var parameterValues = new SqlParameter[] { paramDatabaseName, paramSnapShotPath };

            // SP should be executed from master db
            string masterConnectionString = ConnectionString.Replace(sqlConnection.Database.ToString(), "master");

            SqlHelper.ExecuteDataset(new SqlConnection(masterConnectionString), CommandType.StoredProcedure,
                                                                 spRestoreSnapShot, parameterValues);
        }
}
 

Animate your Silverlight ItemsControl

17 Oct

The idea behind the animation is to inform the users of the new items that were added to the ItemsControl. The new items will fly into the screen from left and right.

Let’s take an existing example from here by Tim Heuer:
Twitter Search Monitor

The ItemsControl in the example consists of a DataTemplate defined in a resource.

Let’s check the following original code snippet from Search.xaml:

            
                
            

If we examine the ItemsControl, we can see that it has a reference to a SearchResultsTemplate Resource. This DataTemplate Resource is defined in the SearchPage. To interact with the items, we need to copy this DataTemplate to a new UserControl.

Now we want to change the reference to the DataTemplate in the Page.Resources to our own UserControl (TwitterItem) in Search.xaml:

 
                
                    
                        
                            
                        
                    
                    
                        
                            
                            
                            
                            
                        
                    
                
            

We can now add some Storyboards to our TwitterItem.xaml:

	

			
				
					
						
					
				
				
					
						
					
				
			
		
		
			
				
				
			
		
	

And we can start the animation in code when our ItemsControl is creating the Items:

public TwitterItem()
        {
            // Required to initialize variables
            InitializeComponent();

            // Global variable to see how many items we already have. Alternate the animation.
            if (((App)App.Current).ItemsCount % 2 == 0)
                FlyLeftToRight.Begin();
            else
                FlyRightToLeft.Begin();
            ((App)App.Current).ItemsCount++;
        }

Here is the final version with some User Interface tweaks. When you search for an item, new items will fade in from left to right and right to left. The application will look up new items each 15 seconds.

TwitterSearchMonitor Animated Source (Visual Studio 2010)

If you’re getting a page not found error, click here to view the application.


Install Microsoft Silverlight


 

Microsoft REMIX 2010 Affligem (Belgium)

13 Oct

REMIX10, September 28th, 2010

Microsoft free event

REMIX Belgium started 3 years ago. It is a free event and if you are interested in microsoft web technologies it’s a great opportunity to pick up some knowledge.
The topics are brought by several microsoft certified speakers.

There are two tracks you can choose from (you can mix session if you want).
- UX Track
- Web developer track

Sessions followed:
Introduction (Luc Van de Velde, Katrien De Graeve)
The introduction was spectacular with demos about Internet Explorer 9 (Beta), Microsoft Kinect and the Windows 7 Phone.

Internet Explorer and HTML5: A Lap Around Windows Internet Explorer 9 For Developers (Pete LePage)
Seems like Microsoft has put a lot of efforts in the new version of Internet Explorer 9. Luckily it’s looking very clean and the performance is as good as other browsers.

UX Super Powers with Expression Blend 4 (Arturo Toledo)
I would really improve my design skills and that’s the reason why I followed an UX Track. Expression Blend is another program that you need to learn. It will take some time before you know every bit, but the session gave a pretty good and brief explanation of what you can do.

Building for the cloud: integrating an application on Windows Azure (Maarten Balliauw)
Developing for the Windows Azure platform is the future. Anyways, if you don’t pay attention, you can pay a lot for the resources used on the platform. Scalability in Windows Azure isn’t built-in but you can easily scale your server loads in code.

Using WebGallery, WebDeploy and IIS Extensions (Luis Alves Martins)
Nice introduction about IIS but as I already know a lot of IIS it wasn’t really useful to me.

Overall it’s a nice event. Some sessions might not be very in depth, but it’s always nice to see new technologies and other people’s work.

 
 

Error 403 Forbidden SharePoint WSS Problem

01 Sep

This is a common scenario… it works on my machine but on another environment the application just refuses to work…

Well, I had a tough problem to solve lately. I was using WSS Application Pages and whenever I visit my application page, it gave me an error 404. I could even debug the code on the machine but it completes without an error and afterwards it just turned out to be a 404 in the browser.

The other pages were working fine… only this one was failing. I almost gave up on this but then I remembered it was the only page using AJAX.

The AjaxControlToolkit.dll wasn’t in the GAC. I really don’t understand why this isn’t logged anywhere. EventViewer? SharePoint Logs? Failure on debug? Nothing.

Anyways, make sure you have all your dlls in your bin folder or GAC.

 

Multiple RDP Sessions in Windows 2008 R2

16 Aug

Terminal Services in Windows Server 2008 R2 becomes Remote Desktop Services (source). This is a bit confusing especially if you want to setup multiple concurrent remote desktop connections.

In order to allow this on Windows 2008 R2 perform the following steps:
- Start -> Administrator Tools -> Remote Desktop Services -> Remote Desktop Services Host Configuration
- Double click the “Remote Desktop Licensing Mode” under the “Licensing” Title
- Uncheck the default behaviour of “Restric each user to a single session”.

Configuring Multiple Remote Desktop Sessions

Now you can connect with 2 clients to the same machine without loosing your session.

 
 

System.NotSupportedException when referencing to an assembly

11 Aug

You receive the following exception in Visual Studio 2010:

System.NotSupportedException: An attempt was made to load an assembly from a network location which would have caused the assembly to be sandboxed in previous versions of the .NET Framework.

This release of the .NET Framework does not enable CAS policy by default, so this load may be dangerous. If this load is not intended to sandbox the assembly, please enable the loadFromRemoteSources switch. See http://go.microsoft.com/fwlink/?LinkId=155569 for more information.

When you try to reference binaries that were zipped on another machine you must check for blocked files:
Zip File that has blocked files

When you unlock the zip file and use the unblocked binaries, it should work.