January, 2011 Archives

31
Jan

To test or not to test

by Mikael Lundin in Programming

I seem to answer this question over and over.

How much effort should be put into unit testing.

And my answer is always the same.

You should write the test if the test has a higher value than the cost of writing it.

Now, this depends on the developer, how good he is at writing automatic tests. This might not be true for any of the tests of a novice unit tester. Then again, it is a investment – learning to unit test.

The novice tester would follow up with the question, “How do I know that the test will be worth more than the effort producing it?”. 20% of the tests that you write will count up for 80% of the value. Just focus on the right 20%.

This rule can be made general

You should not do task X if the value of X does not exceed the effort of doing it.

26
Jan

How to UnitTest your WebControls rendered html

by Mikael Lundin in Programming

Testing ASP.NET code is always hard. How do you test that a control renders the HTML that you require? I will show you how. Let’s use the ULRadioButtonList that I have written about earlier and test that it outputs the expected markup.

The schema that validates the markup

The downside of using a XSD schema to validate HTML, is that HTML 5 is not XML as XHTML was. There’s not much we can do about that except writing our controls markup as if it where strict XHTML.

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="UnorderedRadioButtonList"
    targetNamespace="urn:unordered-radio-button-list"
    elementFormDefault="qualified"
    xmlns="urn:unordered-radio-button-list"
    xmlns:mstns="http://www.litemedia.se/UnorderedRadioButtonList.xsd"
    xmlns:xs="http://www.w3.org/2001/XMLSchema">

  <!-- Root element -->
  <xs:element name="ul">
    <xs:complexType>

      <!-- Unbounded number of elements -->
      <xs:sequence maxOccurs="unbounded">
        <xs:element ref="li" />
      </xs:sequence>
    </xs:complexType>
  </xs:element>

  <!-- The LI element-->
  <xs:element id="li" name="li">
    <xs:complexType>
      <xs:sequence>
        <xs:element ref="input" />
        <xs:element ref="label" />
      </xs:sequence>
    </xs:complexType>
  </xs:element>

  <!-- input element has only attributes -->
  <xs:element id="input" name="input">
    <xs:complexType>
      <xs:attribute name="id" type="xs:string"></xs:attribute>
      <xs:attribute name="name" type="xs:string"></xs:attribute>
      <xs:attribute name="type" type="xs:string" fixed="radio"></xs:attribute>
      <xs:attribute name="value" type="xs:string"></xs:attribute>
    </xs:complexType>
  </xs:element>

  <!-- label contains for attribute and content -->
  <xs:element id="label" name="label">
    <xs:complexType>
      <xs:simpleContent>
        <xs:extension base="xs:string">
          <xs:attribute name="for" type="xs:string"></xs:attribute>
        </xs:extension>
      </xs:simpleContent>
    </xs:complexType>
  </xs:element>
</xs:schema>

If you think XSD coding is hard, I recommend that you start with writing the XML that you are specifying and then write the XSD to fit that XML. In Visual Studio you will get feedback at once, if your XML does not fit the XSD.

<?xml version="1.0" encoding="utf-8" ?>
<ul xmlns="urn:unordered-radio-button-list">
  <li>
    <input id="bananas" name="bananas" type="radio" value="Bananas"  />
    <label for="bananas">I like bananas</label>
  </li>
  <li>
    <input id="onions" name="onions" type="radio" value="Onions"  />
    <label for="onions">I like onions</label>
  </li>
</ul>

Make sure that you add these files to your project as Embedded Resource, since they’re not interesting for anything except your test.

Writing that test

Now we would like to use our schema to validate output of the web control. This is done with the following code.

namespace LiteMedia.Web.UI.WebControls.Test
{
    using System.IO;
    using System.Reflection;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Xml;
    using NUnit.Framework;
    using System.Xml.Schema;

    [TestFixture]
    public class UnorderedRadioButtonListShould
    {
        /* This private class is used to reach protected members in our SUT */
        private class Template : ULRadioButtonList
        {
            public new void Render(HtmlTextWriter htmlTextWriter)
            {
                base.Render(htmlTextWriter);
            }
        }

        [Test]
        public void ProduceExpectedHtmlMarkup()
        {
            /* Prepare some static variables */
            const string Xmlns = "urn:unordered-radio-button-list";
            var schema = GetType().Namespace + ".UnorderedRadioButtonList.xsd";

            /* Radio button list data source
             * <input type="radio" value="Bananas" /><label>I like bananas</label>
             * <input type="radio" value="Onions" /><label>I like onions</label>
             */
            var data = new ListItemCollection
            {
                new ListItem("I like bananas", "Bananas"),
                new ListItem("I like onions", "Onions")
            };

            /* SUT */
            var control = new Template { DataSource = data  };
            control.DataBind();

            /* Prepare render output stream */
            var htmlOutputStream = new MemoryStream();
            var htmlOutputStreamWriter = new StreamWriter(htmlOutputStream);
            var htmlWriter = new HtmlTextWriter(htmlOutputStreamWriter);

            /* Test */
            control.Render(htmlWriter);
            htmlWriter.Flush();

            /* Assert */
            htmlOutputStream.Position = 0; /* Reset stream */

            /* Load the schema */
            var xsdStream = Assembly.GetExecutingAssembly().GetManifestResourceStream(schema);
            var xmlSchema = XmlReader.Create(xsdStream);

            /* Create xml reader and set schema for validation */
            var settings = new XmlReaderSettings();
            settings.Schemas.Add(Xmlns, xmlSchema);
            settings.ValidationType = ValidationType.Schema;

            // Trigger this event on schema validation errors
            settings.ValidationEventHandler += HandleValidationErrors; 

            // Read and validate htmlOutputStream
            var xmlValidatingReader = XmlReader.Create(htmlOutputStream, settings);
            while (xmlValidatingReader.Read()) ;
        }

        private void HandleValidationErrors(object sender, ValidationEventArgs e)
        {
            // There was validation errors, fail with message
            Assert.Fail(e.Message);
        }
    }
}

This looks really cool, but it is completely useless because it will never fail. That is because the HTML is not associated with that schema.

Change the web control

We have to change our system under test to allow this kind of validation. We need to add xmlns=”urn:unordered-radio-button-list” to the root element to apply the validation. But, we don’t want this when we render in page. I propose that you add a property called Xmlns and only render its contents on the ul node when it is not null.

var ul = string.Format("
",
    string.IsNullOrEmpty(cssClass) ? string.Empty : string.Format(@" class=""{0}""", cssClass),
    string.IsNullOrEmpty(xmlns) ? string.Empty : string.Format(@" xmlns=""{0}""", xmlns));

Now you will initialize the web control with the following.

const string Xmlns = "urn:unordered-radio-button-list";
var control = new Template { DataSource = data, Xmlns = Xmlns };

Now we have a test that will validate that the web control renders expected markup. Pretty powerful huh!
The whole solution can be downloaded from my repository on bitbucket.

22
Jan

Create your own custom NUnit build activity for Team Build 2010

by Mikael Lundin in Programming

There was an awkward moment when I realized that TFS 2010 does not support proj build files anymore. Now you’re supposed to use Workflow Foundation for managing Team Build. Sadly, we have a quite big and complex build setup that we had to convert.

Setting up such a build is not easy, and writing your own custom build activities (previously known as build tasks) is not trivial. That’s why I would like to guide you through how it’s done.

Create a new build definition

Creating the build definition works much the same as it did with TFS2008. Right click on Build in Team Explorer and select “New Build Definition”. For this tutorial I will create a new Contiuous Integration build.

The interesting part about this dialog is the “Process” screen. Here you can specify input arguments to your build process, which is very useful. Make sure that you create a copy of the Default Template to build your custom build upon.

You can now edit your build activity by just double clicking the xaml file in the source control explorer. Neat!

Create your custom activities project

Building custom activities is easiest by creating a new Workflow Activities Library project.

Make sure that you Add References from your project to the following

  • Microsoft.TeamFoundation.Build.Workflow
  • (C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\PrivateAssemblies\Microsoft.TeamFoundation.Build.Workflow.dll)
  • Microsoft.TeamFoundation.Build.Client
    (C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\ReferenceAssemblies\v2.0\Microsoft.TeamFoundation.Build.Client.dll)

You should also change the Target framework of your project to .NET Framework 4. (it is .NET Framework 4 Client Profile) by default.

Create your first custom activity

I want to build an NUnit test runner activity, so I will name my first activity NUnit. Right click on your project and Add a New Item. In the Add New Item dialog select Activity.

You should prioritize Activities before Code Activities for Team Build as it will have an easier time to stop a build with xaml Activities.

In the Toolbox you will find several standard Activites that comes with .NET. Add the Team Build activites by right clicking on the Toolbox and select “Choose Items”. Under System Activities Components you can browse for Microsoft.TeamFoundation.Build.Workflow and add those Activities to the Toolbox.

Once in Toolbox, drag the InvokeProcess activity onto the workflow.

I set its properties like this.

A few things to note

  • The argument testAssembly in “Arguments” will be supplied as an argument to the custom activity
  • I choose to assume that NUnit is installed in its default location. A more ideal situation would be to take path to nunit-console.exe as an argument to the custom activity, since it could be checked in with the source code. (which you would do if you expect a certain version of NUnit or can’t install it on the build machine)
  • nunitExitCode is the argument output that tells the build how the unit test session went. 0 is ok, and everything else is an error.
  • Working directory is also supplied as an argument

Custom activity arguments

So we need to specify arguments for this custom build activity.

Also notice that I’ve added “WriteBuildMessage” and “WriteBuildError” to the Invoke activity. This will log everything that NUnit write to the build log. Handy when you need to follow up on errors.

Add the custom activity to your build

Before we add the custom activity to your build we need to create a partial code behind file. Don’t ask me why, but Team Build will not accept your activity without it. Go ahead and create a new class that looks like this.

namespace BuildActivities
{
    [Microsoft.TeamFoundation.Build.Client.BuildActivity(
        Microsoft.TeamFoundation.Build.Client.HostEnvironmentOption.All)]
    public partial class NUnit
    {
    }
}

This will enable Team Build to load your custom activity as a build activity. Compile your project and open up your team build process.

Add your task to “Run On Agent”. If you’re unable to add your task, there’s a trick of adding the build process xaml to your project with “Add Existing Item … As Link”. After recompiling you should be able to add your custom activity to the build process.

Tell Team Build about your custom activities assembly

Last you need to tell the Team Build Controller about your custom build activity. Right click on the build node in Team Explorer and select “Manage Build Controllers”.

Copy your assembly to that directory and check it into source control.
Congratulations! You have created your first Team Build Activity. Let it not be your last!

Salutations!

I would like to share a link to Ewald Hofman’s excellent guide to Team Build 2010 as it has helped me a lot in my struggles. His tip about using executing powershell scripts from Team Build is very useful.

http://www.ewaldhofman.nl/post/2010/04/20/Customize-Team-Build-2010-e28093-Part-1-Introduction.aspx

14
Jan

Communicate your e-mail

by Mikael Lundin in F#, Programming

For anyone to contact you they need to know how. That’s why you should display your e-mail everywhere. Except … you will get a lot of spam because e-mail is not secure by default.

The e-mail protocols are flawed and that is why there are spammers, constantly scanning the web for new e-mail addresses for sending crap to.

What alternatives do you have communicating your e-mail address on the web, without handing it over to spammers framed in gold?

Content information as an image

Spammers are lazy. If it takes too much effort to extract an e-mail they will skip it, because there are millions more waiting. Easiest way to protect your e-mail address from spammers is to put it in an image like below.

Cons

  • You can’t mark and copy the e-mail address into your e-mail client. You’ll have to type it out manually.
  • The image can’t be percieved by blind people or other kinds of screen readers.

Use scripts to display e-mail

Since spambots very seldom execute client side scripts on a page it would be safe to create a placeholder on the page and replace the contents with the e-mail. You could do it with javascript, or Flash, Silverlight if you want to make it even harder to parse out it with a bot.

<html>
	<body>
		<span id="email">[Email Placeholder]</span>
		<script type="text/javascript">
			document.getElementById('email').innerText = "spam@litemedia.se";
		</script>
	</body>
</html>

Cons

  • Today, most browsers are able to run scripts and most companies allows their employees to run javascript, but this is not unobtrusive javascript. If you turn of javascript, content of the page will change.

Convert to HTML Literals

Most of the bots are quite stupid. They download the html page and run a regex looking for e-mail addresses. If your e-mail address does not look like an e-mail address they will not find it. That’s why you could convert every character in your e-mail address to ascii html literals.

Here’s how to do the conversion in F#.

let encode (s : string) =
    s
    |> Seq.map (fun c -> System.String.Format("&#{0:d};", c |> int))
    |> System.String.Concat

> encode "spam@litemedia.se";;
val it : string =
  "&#115;&#112;&#97;&#109;&#64;&#108;&#105;&#116;&#101;&#109;&#101;&#100;&#105;&#97;&#46;&#115;&#101;&quot

This is what my e-mail will look like after being rendered in a browser: spam@litemedia.se

Cons

  • A really clever bot will look for the @ literal &#64; and parse out the rest of the e-mail address. That is however not very likely since it is too much work and there are millions of unprotected e-mails waiting.
13
Jan

Functional Patterns in C#: MapWhile

by Mikael Lundin in Programming, Project Euler

I had already solved Project Euler 23 in F# but wanted to translate my solution to C# for a friend. Those translations always tend to become very functional.

This time around I needed a MapWhile method. This method should take a list and map a function over all elements as long as the while condition is true. This is actually very simple to implement, if you know how.

public static class Extensions
{
    public static IEnumerable<T> MapWhile<T>(this IEnumerable<T> list, Func<T, T> mapFunction, Func<T, bool> whilePredicate)
    {
        return MapWhile(list, (i, item) => mapFunction(item), (i, item) => whilePredicate(item));
    }

    public static IEnumerable<T> MapWhile<T>(this IEnumerable<T> list, Func<int, T, T> mapFunction, Func<int, T, bool> whilePredicate)
    {
        var enumerator = list.GetEnumerator();
        var index = 0;

        while (enumerator.MoveNext())
        {
            if (!whilePredicate(index, enumerator.Current))
            {
                break;
            }

            yield return mapFunction(index, enumerator.Current);
            index++;
        }
    }
}

And some unit tests on usage.

[TestFixture]
public class MapWhileShould
{
    [Test]
    public void ReturnAtEndOfList()
    {
        /* Setup */
        var list = new[] { 1, 2, 3, 4 };

        /* Test */
        var result = list.MapWhile(x => x * 2, x => true);

        /* Assert */
        Assert.That(result.Sum(), Is.EqualTo(20));
    }

    [Test]
    public void BreakWhenWhileConditionIsFalse()
    {
        /* Setup */
        var list = new[] { 1, 2, 3, 4 };

        /* Test */
        var result = list.MapWhile(x => x * 2, x => x < 3);

        /* Assert */
        Assert.That(result.Sum(), Is.EqualTo(6));
    }

    [Test]
    public void ReturnEmptyListWhenWhileConditionIsFalseByDefault()
    {
        /* Setup */
        var list = new[] { 1, 2, 3, 4 };

        /* Test */
        var result = list.MapWhile(x => x * 2, x => false);

        /* Assert */
        Assert.That(result.Count(), Is.EqualTo(0));
    }

    [Test]
    public void WorkWithStrings()
    {
        /* Setup */
        var list = new[] { "Hello", "World", "Santa", "Claudius" };

        /* Test */
        var result = list.MapWhile((i, s) => i % 2 == 0 ? s.ToUpper() : s, (i, s) => true);

        /* Assert */
        Assert.That(string.Join(string.Empty, result), Is.EqualTo("HELLOWorldSANTAClaudius"));
    }
}

Usage in Project Euler 23

This is how I solved Project Euler 23 with the MapWhile function. This is not the most effective solution imaginable, but it is short and readable.

private const int AbundantSumMax = 28123;

public static void Main(string[] args)
{
    // Just create this once
    var defaultRange = Enumerable.Range(1, AbundantSumMax);

    // Returns true if n is abundant
    Func<int, bool> isAbundant = n => Enumerable.Range(1, n / 2).Where(x => n % x == 0).Sum() > n;

    // Get all abundants up to 28123
    var abundants = defaultRange.Where(isAbundant).ToList();

    // Get abundant sums
    var abundantSums = GetAbundantSums(abundants);

    // Invert abundant sums
    var result = defaultRange.Except(abundantSums).Sum();

    // Print
    Console.WriteLine("Result: {0}", result);
}

private static IEnumerable<int> GetAbundantSums(IList<int> abundants)
{
    // Unique set of numbers
    var result = new HashSet<int>();

    // The Tortoise and the Hare
    foreach (var abundant in abundants)
    foreach (var abundantSum in abundants.MapWhile(x => x + abundant, x => x <= abundant))
    {
        result.Add(abundantSum);
    }

    return result;
}

You can find my F# solution at bitbucket.