Stop doing TDD and start doing BDD with SharePoint!

I’m certainly one of those guys that like to do TDD and If you ask people what differentiates me from other developers you will almost certainly get the answer that I’m really serious about quality.  

But after my last project I’ve been become “wiser” or more careful with what kind of tests to use when and where. So why the unusually provoking title?

Last week I got a tweet from my friend Johan about tips on how to do TDD in SharePoint with assemblies that reside in the GAC.Stop doing TDD and start doing BDD with SharePoint

For a brief second I thought that I would just give him a list with the different methods/hacks/workarounds I’ve seen and then I thought:

“you’re only fighting the symptoms, we deserve better”

SharePoint lacks good mockable Interfaces and serves you with lots of sealed classes and static classes. That’s not a great foundation for TDD.

Furthermore we have the whole GAC thingy, also not a great foundation for TDD. If only I would have received a euro for every time someone in my last project asked me why the tests were not passing and whereby I asked “do you have an older assembly in the GAC?”

I can’t see how trying to do TDD in SharePoint will lead to anything but workarounds or hacks to get it working.

Another aspect of truly doing TDD is that you really need a vast knowledge of the domain and IMHO very few developers doing SharePoint development have the necessary knowledge.

In fact I did a test with two groups in my last SharePoint project. Both groups were told to TDD a small Document Set feature. Both groups were given 1½ hour. I coached the second team and 5 min into the exercise I told my group that let’s skip TDD and just do the feature.

The result was spectacular as you might have guessed. The first group almost didn’t make any progress at all and the second group didn’t come very far either. Why? Not enough knowledge of the domain and no mockable interface makes it almost impossible to do TDD in my opinion.

Still not convinced? Well it’s a free world go ahead, try it, fail and become wiser yourself.

I’ll even give you some methods I’ve used/seen/hacked/worked around the last couple of years (without any specific order of importance):

  1. Set Assembly version to 1.0.0.*, this way you won’t have any issues with the GAC thingy. But you’ll have lots of other side effects that you need to mitigate/automate.
  2. Retract dll’s in test setup/teardown.
  3. Write you class under test in the test project and then move it. Johan wrote about a great spin-off on this method here.
  4. Wrap SharePoint artifacts with your own Interfaces.
  5. Separate your domain from the infrastructure, and TDD the domain object only leave the infrastructure alone!
  6. Use a mocking technology like Fakes/Shims/Moles/TypeMock. This demands a really deep knowledge and understanding of SharePoint so if you think this is something you’d like to try, I say beware you’re treading in deep dark waters.

What you should do instead is to treat SharePoint as the framework it is much like the way you would treat the .Net Framework.

BDD is a nice way to do this, you invest more time in designing behaviors or capabilities of your application using SharePoint as one of those capabilities.

But that’s just my very personal 2  cents,

Hugo

How Do I Do Moles?

Background

I’ve just recently started my first Open Source project (there I said it now I definitely have to deliver it). I can go so far to say that it has something to do with TFS 2010 and a Visual Studio package. I got you curious now right! Anyway there are some challenges to be solved when integrating your own code with existing APIs like the TFS Client API, it’s hard to unit test right? Well some would argue that you shouldn’t care to test your interaction with other APIs but for me that’s not an option. So I’ve chosen 2 basic strategies:

  1. Wrap the TFS Client API with my own classes and Interfaces.
  2. Test my own classes with the help from Moles. Moles is a Mocking framework from Microsoft Research.

I’ve written about my experiences with Moles here and you should really read that post if you’ve never used Moles before and want to continue reading this post.

A simple wrapper class

Lets start off with a very simple wrapper class that enables you to connect to a TFS 2010 instance.

using System;
using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Framework.Common;

namespace HugoHaggmark.Blog.Moles.HowDoIDoMoles
{
    public class TfsConnectionWrapper
    {
        private TfsTeamProjectCollection tfsTpc;
        public TfsConnectionWrapper()
        {
        }
        public void Connect(string url)
        {
            tfsTpc = TfsTeamProjectCollectionFactory.GetTeamProjectCollection(new Uri(url));
            tfsTpc.Connect(ConnectOptions.None);
            tfsTpc.EnsureAuthenticated();
        }
    }
}

As you can see this wrapper class uses some TFS Client API like the call to TfsTeamProjectCollectionFactory.GetTeamProjectCollection for instance. Well if we take a close look at TfsTeamProjectCollectionFactory we’ll find the following declaration:


using System;
namespace Microsoft.TeamFoundation.Client 
{ 
    public static class TfsTeamProjectCollectionFactory 
    { }
}

As you can clearly see TfsTeamProjectCollectionFactory is a static class with now chance of sub classing or extending to enables some sort of mocking. So this is really where a mocking framework like Moles comes to play.

Before we start looking at any unit test code I must confess that I’ve started to categorize all my unit tests that use Moles with a test category called MolesTest. I started using the

[TestCategory(“MolesTest”)]

notation at first but then I just created my own TestCategoryAttribute like this:

using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace HugoHaggmark.Blog.Moles.HowDoIDoMoles.Tests
{
    public sealed class MolesTestAttribute : TestCategoryBaseAttribute
    {
        public override IList<string> TestCategories
        {
            get { return new[] { "Moles" }; }
        }
    }
}

Doing this enables me to just add MolesTest next to all my TestMethod attributes like so which makes it easy to filter Moles tests if necessary.

[TestMethod, MolesTest]

 

How I used to do Moles

The following example illustrates how I used to use Moles as part of my unit testing. (by the way looking at this code now makes my body shiver with disgust)

using System;
using System.Net;
using Microsoft.TeamFoundation.Client.Moles;
using Xunit;
namespace HugoHaggmark.Blog.Moles.HowDoIDoMoles.Tests
{
    [Microsoft.VisualStudio.TestTools.UnitTesting.TestClass]
    public class TfsConnectionWrapperTests
    {
        private const string validUrl = "http://valid";
        [Microsoft.VisualStudio.TestTools.UnitTesting.TestMethod, MolesTest]
        [Microsoft.VisualStudio.TestTools.UnitTesting.HostType("Moles")]
        public void using_an_valid_url_string_should_not_throw_the_old_way_I_used_to_do_moles()
        {
            Assert.DoesNotThrow(() =>
            {
                MTfsTeamProjectCollection mole = new MTfsTeamProjectCollection();
                MTfsConnection.AllInstances.ConnectConnectOptions = (connection, options) => { };
                MTfsConnection.AllInstances.EnsureAuthenticated = (connection) => { };
                MTfsTeamProjectCollectionFactory.GetTeamProjectCollectionUri = (uri) =>
                {
                    if (uri.Equals(new Uri(validUrl))) return mole;
                    throw new WebException();
                };

                TfsConnectionWrapper wrapper = new TfsConnectionWrapper(); wrapper.Connect(validUrl);
            });
        }
    }
}

Let’s go through a couple of things before I completely throw this in the recycle bin for ever:

  1. Yes I’m using xUnit.net as my preferred Assert framework, because I think it’s more descriptive then the default in Visual Studio and it makes the transition to xUnit.net in the future simpler. And because of that I need to prefix all my attributes with Microsoft.VisualStudio.TestTools.UnitTesting. So why not use xUnit all the way? Well that’s a whole other future blog post to be written. Let’s stick with fact that the combination xUnit, Moles and TFS Build and getting stuff published back to TFS caused me some serious headache in the past and that deserves a place in an other post.
  2. I’m not going to bother right now verifying the input to the Moles delegates except for the MTfsTeamProjectCollectionFactory.GetTeamProjectCollectionUri delegate where I want to make sure that any invalid uri throws.
  3. This would be my starting point then I would probably write another test method to make sure that passing invalid url would indeed throw an exception. In creating that second method I would of course refactor all my moles setups into separate methods. The end result would look something like so:
using System;
using System.Net;
using Microsoft.TeamFoundation.Client.Moles;
using Xunit;
namespace HugoHaggmark.Blog.Moles.HowDoIDoMoles.Tests
{
    [Microsoft.VisualStudio.TestTools.UnitTesting.TestClass]
    public class TfsConnectionWrapperTests
    {
        private const string validUrl = "http://valid";
        [Microsoft.VisualStudio.TestTools.UnitTesting.TestMethod, MolesTest]
        [Microsoft.VisualStudio.TestTools.UnitTesting.HostType("Moles")]
        public void using_an_valid_url_string_should_not_throw_the_old_way_I_used_to_do_moles()
        {
            Assert.DoesNotThrow(() =>
            {
                SetupAllMoles();
                TfsConnectionWrapper wrapper = new TfsConnectionWrapper();
                wrapper.Connect(validUrl);
            });
        }

        [Microsoft.VisualStudio.TestTools.UnitTesting.TestMethod, MolesTest]
        [Microsoft.VisualStudio.TestTools.UnitTesting.HostType("Moles")]
        public void using_an_invalid_url_string_should_throw_the_old_way_I_used_to_do_moles()
        {
            Assert.Throws<WebException>(() =>
            {
                SetupAllMoles();
                TfsConnectionWrapper wrapper = new TfsConnectionWrapper();
                wrapper.Connect("http://invalidurl");
            });
        }

        private static void SetupAllMoles()
        {
            SetupConnectMole();
            SetupEnsureAuthenticatedMole();
            SetupGetTeamProjectCollectionUriMole();
        }

        private static void SetupConnectMole()
        {
            MTfsConnection.AllInstances.ConnectConnectOptions = (connection, options) => { };
        }

        private static void SetupEnsureAuthenticatedMole()
        {
            MTfsConnection.AllInstances.EnsureAuthenticated = (connection) => { };
        }

        private static void SetupGetTeamProjectCollectionUriMole()
        {
            MTfsTeamProjectCollection mole = CreateTeamProjectCollectionMole();
            MTfsTeamProjectCollectionFactory.GetTeamProjectCollectionUri = (uri) =>
            {
                if (uri.Equals(new Uri(validUrl)))
                    return mole;
                throw new WebException();
            };
        }

        private static MTfsTeamProjectCollection CreateTeamProjectCollectionMole()
        {
            return new MTfsTeamProjectCollection();
        }
    }
}

So in the past I would feel reasonably happy with this and then move on with the next test case. But then I would come to a point that other test classes needed the same Moles setup and then I would create a class that all test classes derived from. Phuu…there had to be a better approach and as I never settle and always seek ways to improve my skills and code I’ve now reached an approach that for the moment feels comfortable.

Introducing Testable Moles classes

Nowadays I just create base classes that derive from (if possible) a Moles class. This way I can define my default behavior for my Testable Moles class and reuse it in any other test classes. And by marking the methods in the class used in the Moles delegates as virtual I can create different Testable Mole classes. Clever right? Let’s take a look at my implementation of a base class for a TestableTfsConnectionBase:

using Microsoft.TeamFoundation.Client;
using Microsoft.TeamFoundation.Client.Moles;
using Microsoft.TeamFoundation.Framework.Common;
namespace HugoHaggmark.Blog.Moles.HowDoIDoMoles.Tests
{
    internal abstract class TestableTfsConnectionBase : MTfsConnection
    {
        protected TestableTfsConnectionBase()
            : base(new MTfsTeamProjectCollection())
        {
            InitConnectMole();
            InitEnsureAuthenticatedMole();
        }

        private void InitEnsureAuthenticatedMole()
        {
            AllInstances.EnsureAuthenticated = (connection) =>
            {
                SetupEnsureAuthenticatedMole(connection);
            };
        }

        private void InitConnectMole()
        {
            AllInstances.ConnectConnectOptions = (connection, options) =>
            {
                SetupConnectMole(connection, options);
            };
        }

        protected virtual void SetupConnectMole(TfsConnection connection, ConnectOptions options)
        {
        }

        protected virtual void SetupEnsureAuthenticatedMole(TfsConnection connection)
        {
        }
    }
}

After this I would just go ahead and create a “default” test class

namespace HugoHaggmark.Blog.Moles.HowDoIDoMoles.Tests 
{ 
    internal class TestableTfsConnection : TestableTfsConnectionBase 
    { 
    } 
}

and if I need I can create another class that implements another behavior like the following class that always throws when trying to connect:

using System; 
using Microsoft.TeamFoundation.Client; 
using Microsoft.TeamFoundation.Framework.Common; 
namespace HugoHaggmark.Blog.Moles.HowDoIDoMoles.Tests 
{ 
    internal class TfsConnectionThatThrowsOnConnect : TestableTfsConnectionBase 
    { 
        protected override void SetupConnectMole(TfsConnection connection, ConnectOptions options) 
        { 
            throw new DivideByZeroException(); 
        } 
    } 
}

I hope you get the picture on how the testable classes works. Now let’s return to our unit test class and see how this would look in practice:

[Microsoft.VisualStudio.TestTools.UnitTesting.TestMethod, MolesTest] 
[Microsoft.VisualStudio.TestTools.UnitTesting.HostType("Moles")] 
public void using_a_connection_that_always_throws_should_throw_the_new_way_I_use_moles() 
{ 
    Assert.Throws<DivideByZeroException>(() => 
    { 
        MolesFactory.SetupMole<TfsConnectionThatThrowsOnConnect>(); 
        MolesFactory.SetupMole<TestableTfsTeamProjectCollection>(); 
        MolesFactory.SetupMole<TfsTeamProjectCollectionFactoryThatNeverThrows>(); 
        TfsConnectionWrapper wrapper = new TfsConnectionWrapper(); 
        wrapper.Connect("http://invalidurl"); 
    }); 

As you can see any new test method would just simply initialize any testable mole class needed and then of you go. I made a small class called MolesFactory that simply creates an instance of the supplied type in the SetupMole just because I believe it makes my code more descriptive and readable. The complete solution with code and binaries can be downloaded from here.

This is the first time I reveal my inner thoughts and code approaches so I really hope you got a clear understanding and some inspiration. Really looking forward to get feedback from the Moles community regarding the approaches described in this post.

Until next time,

Hugo

BDD Bonanza with SpecFlow, SpecLog and TFS, huh?

Confession

I must admit that title is somewhat provoking and that will certainly get some people really going. Anyway from a TFS perspective I see real potential in the integration between SpecLog and TFS and I hope to show this in upcoming posts.

Background

I’ve been using SpecFlow a couple of months and I really like the feeling I get every time a debug my specifications Ler. A colleague of mine Marcus Hammarberg has written lot’s of posts like this and at some point we even did a joint venture that resulting in this post by Marcus and this one by me.

So we had quite a good story for developers at that point and really no nice way to present specification files to testers or business analysts. Well the same team that brought you SpecFlow has also made SpecLog a tool that looks very promising.

Installation

The installation is not completely automated there’re a some manual steps you need to do to make the TFS Integration work. This is certainly a feature I’d really like TechTalk to provide in future releases.

If you are using the MSF Agile process template make sure you’ve downloaded version TechTalk.SpecLog.1.0.63.msi or later. When I couldn’t get the integration to work the guys at support helped me out and after that weekend they released a working version, very impressive indeed!

Installing the MSI

Make sure you’ve logged in on your TFS server. Run the downloaded msi and make sure you select all components like this picture:
image

Create service account

Create a service account like the picture below:image

Give the same service account Log on as a Service rights as the picture shows.

image

After this you have to start a command prompt as Adminstrator and do the following:

  • Add the created account to the [TEAMFOUNDATION]\Team Foundation Service Accounts with the following command
    tfssecurity /g+ “Team Foundation Service Accounts” n:[YOURDOMAIN]\SpecLogSvc ALLOW /server:http://yourtfsserver:8080/tfs
  • Making it possible for the service account to open TCP port 4242 with the following command
    netsh http add urlacl url=http://+:4242/ user=[YOURDOMAIN]\SpecLogSvc

Create a shared folder

Create a shared folder that gives [YOURDOMAIN]\SpecLogSvc contribute rights to that folder like so:

image

Follow the instructions given from TechTalk

In your SpecLog folder you will have two folders, one called Server and one called TFSIntegration. In these folders there’re txt-files that will guide you through the next manual steps you need to get started. Start with server instructions first.

Gotchas

  • The default log path is under %LOCALAPPDATA%\SpecLog so I changed it to the same shared folder created earlier.
  • When you create the windows services you’ll be prompted with username and password. It’s very important to enter the username in the format [YOURDOMAIN]\[ServiceAccount]. Otherwise you’ll get an error.

image

Testing

You have to connect to a shared repository to get the TFS integration working like the picture shows below:

image

Next steps are to start working on your requirements Skrattar! Well I’ve made a simple screen capture that shows how it could look.

image

And If we take a look at the US3 user story we will find this nice overlook. Notice how you can see the TFS source controlled Gherkin file connected to this User Story.

image

The same User Story would look like this in Visual Studio:

image

image

And as you can see the integration works…the service account does all the job:

image

I must say that things are truly starting to come full circle with SpecLog and I hope that my small post will get you started with SpecLog integration with TFS.

I’ll sure keep working with SpecLog, TFS and most importantly people,

Hugo