Unit Testing Silverlight Animation

One thing I haven't really included in any of the example Silverlight posts are the unit tests. There's continuous debate among developers concerning the effectiveness of unit tests, in my opinion they're absolutely necessary whenever you're building an application. Test driven development (TDD) on the other hand I still find very hard, it's a different way to approach development that seems difficult to pick up without peer programming with someone who already has this approach.

In my mind the benefit of unit tests comes months down the track when you're able to use your suite of unit tests in regression testing. The most value you can gain is when a bug is located (and there will be a bug) then the first thing that's done is build a failing test. Now you can fix the bug knowing that you haven't altered any existing expected behavior and your suite of tests is that much stronger for next time.

Anyway I'm rambling, Silverlight unit testing is certainly a different beast than using NUnit etc. The best way to learn about it is from "Unit Testing with Silverlight 2" and "Asynchronous test support - Silverlight unit test framework and the UI thread" two excellent articles from Jeff Wilcox.

In this post I'll run through the tests for AnimationBase and SizeAnimation, there has been some minor refactoring on these classes since they were last shown but nothing major.

First we want to test the AnimationBase class, particularly the it creates a storyboard for the element being animated. Also that if we animate the element multiple times that we don't create more than one storyboard. The tests are as follows:

[TestClass]

public class AnimationBaseFixture : SilverlightTest

{

    [TestMethod]

    public void AnimateAddsAStoryboardToResources()

    {

        var animation = new SimpleAnimation();

        var element = new Button();

 

        Assert.AreEqual(0, element.Resources.Count);

 

        animation.Animate(element);

 

        Assert.AreEqual(1, element.Resources.Count);

        Assert.IsInstanceOfType(element.Resources[animation.StoryboardResourceKey], typeof(Storyboard));

    }

 

    [TestMethod]

    public void MultipleAnimationsDoNotAddMoreStoryboards()

    {

        var animation = new SimpleAnimation();

        var element = new Button();

 

        Assert.AreEqual(0, element.Resources.Count);

 

        animation.Animate(element);

        animation.Animate(element);

 

        Assert.AreEqual(1, element.Resources.Count);

    }

 

    [TestMethod]

    [Asynchronous]

    public void FiresAnimationCompletedEvent()

    {

        var animationCompleted = false;

 

        var animation = new SimpleAnimation();

        animation.AnimationCompleted += (s, e) => animationCompleted = true;

 

        var element = new Button();

 

        EnqueueCallback(() => animation.Animate(element));

        EnqueueConditional(() => animationCompleted);

        EnqueueTestComplete();

    }

}

 

Now we need to test the SizeAnimation class. First we're going to test the simple inputs into the constructor and that exceptions are thrown in the constructor.

[TestMethod]

public void CanConstruct()

{

    var animation = new SizeAnimation(100, 50, TimeSpan.FromSeconds(10));

 

    Assert.AreEqual(100, animation.Width);

    Assert.AreEqual(50, animation.Height);

    Assert.AreEqual(10, animation.Duration.Seconds);

}

 

[TestMethod]

public void CanConstructWithDefaultDuration()

{

    var animation = new SizeAnimation(100, 50);

 

    Assert.AreEqual(AnimationBase.DefaultDuration, animation.Duration);

}

 

[TestMethod]

[ExpectedException(typeof(ArgumentException))]

public void ThrowsExceptionForNegativeWidth()

{

    new SizeAnimation(-10, 50);

}

 

[TestMethod]

[ExpectedException(typeof(ArgumentException))]

public void ThrowsExceptionForNegativeHeight()

{

    new SizeAnimation(100, -50);

}

 

Now the interesting test, we want to test the size is actually animated. To do this we need to use the Asynchronous testing from the Silverlight unit test framework, First we arrange the objects we'll need, the animation and a button to actually animate, we also need to know when the animation is completed so we'll attach a simple lambda to set a bool when it is.

Once the button is created we'll add it to the test panel and quickly Assert that it's at the Width and Height we expect. We'll thenenque the animation and wait until it's completed, then we'll Assert that it's size is the expected, pretty simple really.

[TestMethod]

[Asynchronous]

public void AnimatesSize()

{

    var animationCompleted = false;

 

    var animation = new SizeAnimation(100, 50, TimeSpan.FromMilliseconds(10));

    animation.AnimationCompleted += (s, e) => animationCompleted = true;

 

    var element = new Button

                      {

                          Width = 50,

                          Height = 25

                      };

 

    TestPanel.Children.Add(element);

 

    EnqueueCallback(() => Assert.AreEqual(50, element.Width));

    EnqueueCallback(() => Assert.AreEqual(25, element.Height));

 

    EnqueueCallback(() => animation.Animate(element));

 

    EnqueueConditional(() => animationCompleted);

 

    EnqueueCallback(() => Assert.AreEqual(100, element.Width));

    EnqueueCallback(() => Assert.AreEqual(50, element.Height));

 

    EnqueueTestComplete();

}

 

While the Silverlight unit test framework isn't as easy to get a grips with as something like NUnit given that it needs a browser it's still very useful and makes it quite simple to test our controls.

Silverlight Animation so far:

Shout It Kick It submit to reddit

7 Comments

  1. DotNetKicks.com
    DotNetKicks.com
    Thursday, March 12, 2009
    Trackback from DotNetKicks.com Unit Testing Silverlight Animation
  2. silverlight-travel.com
    silverlight-travel.com
    Thursday, March 12, 2009
    Pingback from silverlight-travel.com Silverlight Travel » Compiled Experience * Home * About * Subscribe * Contact Login Unit Testing Silverlight Animation
  3. DotNetShoutout
    DotNetShoutout
    Thursday, March 12, 2009
    Trackback from DotNetShoutout Unit Testing Silverlight Animation - Nigel Sampson
  4. Justin Angel
    Justin Angel
    Thursday, March 12, 2009
    Nice blog post Nigel. good stuff. Testing animations is an excellent example where doing async UI integration testing differs from doing business unit tests. You've conveyed that brilliantly. One thing though for people reading this article, one of the precepts of unit testing is "Select ain't broken" (comes from people who tested the "Select" phrase in SQL). The concept here is that there's no reason to test animations in real world apps since they must work. But it's a good example none the less. Keep it up, -- Justin Angel Microsoft Silverlight Toolkit Program Manager
  5. Nigel Sampson
    Nigel Sampson
    Friday, March 13, 2009
    Thanks for the comments Justin, I'd agree with you that you shouldn't test something that must work (like Select in SQL) but since SizeAnmation is something I wrote that constructs a Storyboard internally I believe it's a good idea to verify that the storyboard completes the action intended (instead of for instance fading the objec out). Cheers
  6. Stephen Price
    Stephen Price
    Sunday, March 15, 2009
    Brilliant post, a nice simple example of an asyncronous test, exactly what I was looking for. Thanks so much. :) cheers, Stephen
  7. Kelli Garner
    Kelli Garner
    Friday, September 25, 2009
    Great site, how do I subscribe?

Comments are closed