TFS: Automating unit tests as part of the Team Build

In my new project, we're using Team Foundation Server (TFS) as our source code repository and also as our continuous integration (CI) engine.  The CI aspect is handled neatly by Automaton which leaves me to setup the build process (or the Team Build Type, as it is referred to in TFS parlance).  Automated unit tests form the backbone of any decent CI process.  It wasn't entirely straightforward to set these up, so I thought I'd share my experience with the community.

It's worth noting that we are using MS Test for unit tests, i.e. the unit tests built into Visual Studio Team System (VSTS), and not Nunit.  I expected that this would simplify the build process since I wouldn't be integrating Nunit results back into the build report.  This has been the case, but there are a few gotchas.

As stated on MSDN "How to setup a build server":

In order to run tests during build, Team Edition for Testers must be installed on the build computer. In order to run unit testing, code coverage or code analysis, Team Edition for Developers must be installed on the build computer.

I find it quite surprising that I need a Visual Studio installation on the server, but the docs are pretty clear on this point.  Are there any licence implications of this?  The Visual Studio 2005 Team System licensing white paper states:

As part of the build process, Team Foundation Server may run quality tests and/or analysis on the precompiled or compiled code. These tests rely on functionality found within Team System client products, typically within the Team Edition for Software Developers or Team Edition for Software Testers products. These products may be installed on the build machine by licensed users of those products, as long as they are not directly used by any individuals who are not licensed for those products.

In short, licencing is not a problem.

Now unit tests really are just a type of test, so I'm not entirely clear whether I need VS TE for Testers or VS TE for Developers.  I'm planning to do some automated system testing and so I've installed the relevant bits from both editions on our build server.  I'd guess that you really only need VS TE for Developers.

So you would think that now our build server ought to be fully setup and we now ought to be able to execute unit tests.  Well you can, but only if they are part of a test list.  VSTS groups tests into lists and you need to specify (in the TfsBuild.proj file) the name of a test list containing unit tests to execute.  This is clear in the TfsBuild.proj file, where you need:

<MetaDataFile Include="$(SolutionRoot)\Main\Src\Solutions\Server1.vsmdi">

    <TestList>List of Unit Tests</TestList>

</MetaDataFile>

I don't think this is good enough.  It's enough of a problem for me to get developers to write unit tests.  I don't want to have to then get hold of a VS TE for Testers installation (which is the edition that allows you to edit test lists) and then add these unit tests into the appropriate list to get executed.  And it seems that I'm not the only one.  Enough people have complained about this that Buck Hodges (the dev lead for Team Build) has posted some modifications to TFS that allow you to execute all unit tests in a DLL.  These take the form of a DLL containing an updated MS Build task and a revised Microsoft.TeamFoundations.Build.targets file (plus some docs).  Both of these files need to be installed on your build server.  Having done that, you can get rid of the MetaDataFile element in TfsBuild.proj and replice it with:

<TestContainerInOutput Include="%2a%2a\%2a.UnitTests.dll" />

This (rather odd) syntax translates into **\*.UnitTests.dll.  In other words, you can just specify which DLLs contain your unit tests and the Team Build will now execute them all.

February 13 2007

MOSS: Custom commands for the stsadm.exe utility

I'm doing some work with Microsoft Office SharePoint Server (MOSS) and I recently discovered that with MOSS (and WSS v3) the administration utility is extensible.  Stsadm.exe is something that I have a love-hate relationship with, but it's interesting that it's commands work on a provider model.  Tony Bierman has posted all the details on the SharePoint Solutions Blog and Andrew Connell has some real-world examples of custom commands.

I can see these custom commands being really useful in many MOSS deployment scenarios - anyone who has ever tried to write an MSI or a batch file deployment for a SharePoint site will know how invaluable stsadm.exe really is.  Of course it does raise a bootstrapping issue, in that you have to get your custom commands deployed before you can use them for the rest of your deployment.  However, this shouldn't be an insurmountable problem.

January 22 2007

MOSS: Programmatically modifying a shared webpart

On my current project, we create SharePoint sites in response to calls to a particular webservice and there is one site per domain entity.  In this webservice, there is a certain amount of customisation of the site homepage which needs to be done.  In particular, we have an RSS Aggregator web part and we want this to point to a different URL for each site.

I couldn't find anywhere on the web that had a sample of doing this, so I thought I'd blog the solution:

// Reconfigure the RSS Reader to query against the company name

SPLimitedWebPartManager WPMgr = NewSite.GetLimitedWebPartManager("default.aspx", PersonalizationScope.Shared);

foreach (WebPart wp in WPMgr.WebParts)

{

    RSSAggregatorWebPart RssPart = wp as RSSAggregatorWebPart;

    if (RssPart != null)

    {

        string QueryString = HttpContext.Current.Server.UrlEncode(person.Company);

        RssPart.FeedUrl = RssPart.FeedUrl.Replace("company", QueryString);

        WPMgr.SaveChanges(RssPart);

    }

}

 

Clearly NewSite and person.Company are defined higher up in my code, but you can do whatever you want with the FeedUrl property.  To get this to work you need to have references to:

  • System.Web [for System.Web.WebPart and System.Web.UI.WebControls.WebParts.PersonalizationScope]
  • Microsoft.SharePoint [for Microsoft.SharePoint.WebPartPages.SPLimitedWebPartManager]
  • Microsoft.SharePoint.Portal [for Microsoft.SharePoint.Portal.WebControls.RSSAggregatorWebPart]

The list above also shows which namespaces I import through using declarations.

PS. Apologies to anyone who's disappointed at the lack of WPF/E content in my latest posts.  I hope to play some more with that technology soon, but there'll probably be a pre-dominance of MOSS posts in the coming months.  If you are really uninterested in MOSS posts, then make sure you only subscribe to a tagged feed and not to the main one.

January 22 2007

WPF/E: A glass button

Apologies to my readers, but my blog has a been little quiet of late.  Hopefully I'll be able to share the reasons for this with everyone soon!  In the meantime, here's a WPF/E sample I've been meaning to post for some time.

Essentially it's a button that looks like it's made of glass.  The button pulsates when you hover over it and glows when it's pressed.  A picture is worth a thousand words so here it is:

glass-button

I couldn't get a reasonable screen capture of the hover-over effect, so you'll have to take my word for it (or download and run the attached files).

There are a number of XAML elements which go into making up the button.  They are clearly commented in the XAML but the list is as follows:

  • Drop-shadow: an ellipse with a radial gradient of black fading to transparent
  • Button surround: a white ellipse slightly bigger than the green one
  • Black button background: only visible round the edges of the green when the button is pressed
  • Main button colour: the green (or whatever color you want) of the button.  This ellipse is clipped to its initial outline, thus allowing us to move the ellipse slightly for the button press without it overlapping the button surround
  • Top glow: an ellipse with a linear gradient background of white (at the top) fading to transparent.  Smaller than the main button colour and positioned so that the tops are the same
  • Bottom glow: an ellipse the same size as the main button colour but with a linear gradient background of white (at the bottom) fading to transparent.  This is also clipped as per the main button colour.
  • Hover-over glow: an ellipse the same size as the main button colour with a radial gradient background of white (at the centre of the ellipse) fading to transparent.  This is initially transparent.
  • Transparent element for catching mouse events: on top of all of this is a transparent ellipse the same size as the white button surround for catching MouseEnter, MouseLeave, MouseLeftButtonDown and MouseLeftButtonUp events.  This element also contains the Storyboard for the pulsating hover-over effect (although this could be in any XAML element).

Who would've thought a button could be so complex?  I am quite proud of the fact that the actual button colour only appears once in all of the above XAML elements.  So it's a single change if you fancy a red button rather than a green one.

Now all of this is in a canvas and the Loaded event of the canvas calls a JavaScript function.  The other mouse handlers are attached through script.  The script itself is pretty straightforward, but a bit fiddly in places.  The MouseEnter and MouseLeave event handlers just call Begin() and Stop() methods on the Storyboard.  The MouseLeftButtonDown handler has to adjust the position of a number of elements, as well as moving the clipping geometry on a couple of elements so that the clip geometry doesn't move with the element.  The MouseLeftButtonUp handler reverses these effects.

If you want to make this into a proper button (i.e. one that actually does something) then you need to add some script into the MouseLeftButtonUp event handler.  This script could call other script (for client-side actions), make an ASP.Net postback (for server-side actions), trigger an AJAX call (for AJAX apps) or doing anything else you fancy.

Issues I hit: It's not possible to use the RoutedEvent on an EventTrigger to catch anything other than a Loaded event (confirmed by Joe Stegman in the forums).  This is why I need script to call the Begin and Stop methods on my Storyboard.  As a result of this, animations tend to start running as soon as everything is loaded.  This is why one of the first things I do is to stop the animation.

Future enhancements: It's fiddly to put more than one of these on a Canvas.  They can share the script, but not the XAML.  The way forward here may be for the script to create the XAML elements, but this sort of code always looks ugly.  It's also a bit poor that you need to hack an event handler to get the button to do anything.  It would be much better to be able to pass a JavaScript function into the object constructor and have this called appropriately.

As ever, it would be great to hear from anyone who uses this code.

[PS.  I had wanted to post this as a sample you could run, but our blogging software is preventing me from doing this.  Sorry but you'll have to download and run this in order to see it in action.  As I mentioned previously, IE users need to ensure that load this via HTTP and not directly from the filesystem.]

UPDATE: WPF/E is now better known as Silverlight.  An unusual example of Microsoft changing from a clunky codename to a cool product name!

December 22 2006
Newer Posts Older Posts