Windows 8 XAML Tips - Inline data-driving Unit Testing

By Fons Sonnemans, 13-8-2013

While watching the Automated Testing of XAML-Based Windows Store Apps Build session on video I learned something new. There is a new way in Visual Studio 2013 to do data-driven unit testing using the DataRowAttribute. I couldn't find much documentation or samples so I will try to explain it in this blog post.

Calculator App

For this demo I created a 'silly' Calculator Windows Store application which uses C# and XAML. It has a public Calculator class which is used by the MainPage to add or subtract two values. This is the class which I want to unit test.

using System;

namespace UnitTestDemo {

    public class Calculator {

        public int Add(int a, int b) {
            return a + b;
        }

        public int Subtract(int a, int b) {
            return a - b;
        }
    }
}

The MainPage.xaml has two TextBox controls, two Buttons and a TextBlock to show the result in.

<Page x:Class="UnitTestDemo.MainPage"
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
      xmlns:local="using:UnitTestDemo"
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
      mc:Ignorable="d">

    <Grid Background="{StaticResource ApplicationPageBackgroundThemeBrush}">
        <StackPanel VerticalAlignment="Center"
                    HorizontalAlignment="Center">
            <TextBox x:Name="textBoxA"
                     Text="3"
                     Header="A"
                     Margin="3"
                     Width="100" />
            <TextBox x:Name="textBoxB"
                     Text="2"
                     Header="B"
                     Margin="3"
                     Width="100" />
            <Button Content="Add"
                    Width="106"
                    Click="ButtonAdd_Click" />
            <Button Content="Subtract"
                    Width="106"
                    Click="ButtonSubtract_Click" />
            <TextBlock x:Name="textBlockResult"
                       Style="{StaticResource SubtitleTextBlockStyle}"
                       Width="100" />
        </StackPanel>
    </Grid>
</Page>

The MainPage.xaml.cs contains the click eventhandlers which use the Calculator class to execute the Add() and Subtract() methods. These methods are not Monkey proof, they don't contain any logic for checking valid integer input values.

using System;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;

namespace UnitTestDemo {

    public sealed partial class MainPage : Page {

        private Calculator _calc = new Calculator();

        public MainPage() {
            this.InitializeComponent();
        }

        private void ButtonAdd_Click(object sender, RoutedEventArgs e) {
            int result = _calc.Add(int.Parse(textBoxA.Text), int.Parse(textBoxB.Text));
            textBlockResult.Text = result.ToString();
        }

        private void ButtonSubtract_Click(object sender, RoutedEventArgs e) {
            int result = _calc.Subtract(int.Parse(textBoxA.Text), int.Parse(textBoxB.Text));
            textBlockResult.Text = result.ToString();
        }
    }
}

If you run the app it will look like this.

UnitTest Project

Next I added an extra 'Unit Test Library' project to the Solution.

I added a Reference from this UnitTest project to my Windows Store app. This will allow me to create an instance of the Calculator class which I want to test.

I renamed the default generated UnitTest1.cs file containing the UnitTest1 class to CalculatorUnitTest.cs. This will prompt to rename the class name too.

DataRow

In the CalculatorUnitTest class I added two test methods: TestAdd() and TestSubtract(). Both methods are decorated with the TestMethodAttribute. These methods have 3 parameters: a, b and expected. These parameters are used to calculate the result (actual) and to assert whether actual is equal to expected. The methods have also two DataRowAttributes which will be used to execute the test method twice using the given values (test data) for the parameter values. This makes it possible to do inline data-driven unit testing. You don't have to create a database or csv file with the test data.

using System;
using Microsoft.VisualStudio.TestPlatform.UnitTestFramework;
using UnitTestDemo;

namespace UnitTestLibrary1
{
    [TestClass]
    public class CalculatorUnitTest
    {
        [TestMethod]
        [DataRow(1, 2, 3)]
        [DataRow(4, 5, 9)]
        public void TestAdd(int a, int b, int expected)
        {
            Calculator c = new Calculator();
            int actual = c.Add(a, b);

            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        [DataRow(4, 2, 2)]
        [DataRow(4, 1, 1, DisplayName = "Should fail for demo purposes")] 
        public void TestSubtract(int a, int b, int expected) {
            Calculator c = new Calculator();
            int actual = c.Subtract(a, b);

            Assert.AreEqual(expected, actual);
        }
    }
}

When you run all tests you will get a Failed Test report for the TestSubtract method. The expected value should have been set to 3.

Closure

I will use the new DataRow attribute in my Unit Tests a lot. It will help me to write them more easily. I imagine you will do that too.

Cheers,

Fons

Leave a Comment

Leave a Comment
Name
Comment
6 + 8 =

0 Comments

All postings/content on this blog are provided "AS IS" with no warranties, and confer no rights. All entries in this blog are my opinion and don't necessarily reflect the opinion of my employer or sponsors. The content on this site is licensed under a Creative Commons Attribution By license.