in

TFS Advantage

Furthering Continuous Integration Efforts on Microsoft Visual Studio Team System Team Foundation Server

Tim Bassett

  • Creating and using a test base class

    After writing unit tests for awhile, you will observe there are common patterns and common needs.  One way to fulfill some of these needs is to use a “test base class” or an “abstract test class”.  Using such a pattern for MSTest can help you create more robust unit tests with less code.

    The concept is pretty straight forward.  Basically, create a base class that can perform some mundane or defensive programming tasks for you.

    In MSTest, this is accomplished by create a new class (or unit test class) in either your test assembly or a common assembly (that is also a test assembly).  You cannot make it truly abstract (that leads to some funkiness), but you can inherit from in when you create a new unit test class by decorating it with the TestMethod attribute.

    You can push the typical TestContext property up to a base unit test class, as well as provide virtual methods for TestInitialize and TestCleanup.

    Things to think about for you Test Base class:

    ·         Mock out items and clean up all your mocking

    ·         Clean up your dead files

    ·         Add support methods to copy test files

     

    using System;
    using System.Text;
    using System.Collections.Generic;
    using System.Linq;
    using Microsoft.VisualStudio.TestTools.UnitTesting;

    namespace TestSupport
    {
        /// <summary>
        /// Summary description for UnitTest1
        /// </summary>
        [TestClass]
        public class TestBase
        {

            private TestContext testContextInstance;

            /// <summary>
            ///Gets or sets the test context which provides
            ///information about and functionality for the current test run.
            ///</summary>
            public virtual TestContext TestContext
            {
                get
                {
                    return testContextInstance;
                }
                set
                {
                    testContextInstance = value;
                }
            }

            [ClassInitialize]
            public static void MyClassInitialize(TestContext testContext) { }

            [ClassCleanup]
            public static void MyClassCleanup() { }

            protected bool _testInitializedRan;

            [TestInitialize]
            public virtual void MyTestInitialize()
            {
                _testInitializedRan = true;
            }

            [TestCleanup]
            public virtual void MyTestCleanup() { }
        }

        [TestClass]
        public class MyTestClass : TestBase
        {
            [TestMethod]
            public void ShowsThatTestInitializeRan()
            {
                Assert.IsTrue(_testInitializedRan);
            }
        }
    }

     

  • Survey questions for customized training session on Visual Studio 2008 - Unit Testing - TDD - Continuous Integration - Team Foundation Server

    I'm putting on a two day training session for a group where some participants might be completely new to unit testing and/or TDD.  Almost all are new to TFS.  I put together a survey for the participants to gauge my audience.  I thought this might be a useful resource for others for looking into training, thinking about training or perhaps even job interview material.  Here it is in its raw format directly from the survey engine.

     

    TFS Advantage - Continuous Integration Development with Team Foundation Server 2008

     

    How much professional programming experience do you have?
    (Please tick just one of the following boxes)
    • < 1 yr
    • 1 - 2 years
    • 3 - 5 years
    • 6 - 10 years
    • Let's swap stories about the price per megabyte of your first hard drive
    • This question does not apply to my participation in the sessions.

    How much experience (formal or informal) do you have with designing or writing unit tests?
    (Please tick just one of the following boxes)
    • What's a unit test?
    • I've played around with writing a few unit tests in my spare time.
    • Some experience on some project somewhere
    • I participated in writing a lot of unit tests before in my recent project(s) as part of my daily activities
    • It's the first thing I think of before writing production code.
    • Some people like to refer to me as Kent Beck, Jr.
    • This question does not apply to my participation in the sessions.

    Which best describes how you think writing unit tests will impact your software project’s development life cycle?
    (Please tick just one of the following boxes)
    • Writing unit tests is a waste of time.
    • Writing unit tests will ensure our success.
    • Writing unit tests is one activity that helps in our development cycle.
    • Writing unit tests is something quality assurance (QA) should be doing.
    • Writing unit tests is a good idea, but it slows us down too much.
    • This question does not apply to my participation in the sessions.

    Which answer best describes your experience with continuous integration?
    (Please tick just one of the following boxes)
    • What's continuous integration?
    • Someone else's project used that once, it looked intriguing.
    • I worked with it on a project or two in the past.
    • My experience has shown me it's a valuable part of the software development life cycle.
    • This stuff rocks, I should be the build master!
    • This question does not apply to my participation in the sessions.

    Which answer best describes the optimal time to write unit tests in your software development process?
    (Please tick just one of the following boxes)
    • Before you even create the production code.
    • When you are having a tough time figuring out how to design a component of your system.
    • Before you check in your code.
    • When you find a bug in your component.
    • Again, isn't this QA's job?
    • This question does not apply to my participation in the sessions.

    Which answer best describes how many files is a “good” submission to the source code repository participating in a continuous integration process?
    (Please tick just one of the following boxes)
    • A few files, even if the component is just beginning to take shape.
    • No more than ten, otherwise it’s tough to perform a code review.
    • You should be completely done with your component before checking in, so as many files as it takes.
    • Thirty or fewer, one minute per file in the build, you can't wait longer than that.
    • None. With continuous integration, the build server does most of the coding for you.
    • This question does not apply to my participation in the sessions.

    Which answer best describes your perception of the term “TDD” or “test driven development” or “test driven design”?
    (Please tick just one of the following boxes)
    • It's another fad in software engineering we will all have a good chuckle about in five years.
    • I write some pretty solid code, but this is good stuff for junior developers.
    • I'm intrigued, tell me more!
    • I think it will help us produce higher quality software.
    • I think it could be the only way I approach developing software from here on out.
    • Kent Beck, Jr? Some people call me Kent Beck, Sr!
    • This question does not apply to my participation in the sessions.

    If you have a class (managed .net class, unmanaged C++ class, basic unit of code, etc) in your software’s source code that is 200 lines of code, how many lines of test code would you consider being sufficient or reasonable?
    (Please tick just one of the following boxes)
    • about 50 lines
    • about 50 - 150 lines
    • about 150 - 300 lines
    • about 300 - 600 lines
    • about 600 - 1200 lines
    • The more the better, I'm not done writing tests for my first 'hello world' program yet!
    • This question does not apply to my participation in the sessions.

    What would you like to learn from these sessions? (Feel free to mention specific technologies, methodologies, patterns, etc.)
    _____________________________________________________________________
    _____________________________________________________________________
    _____________________________________________________________________
    _____________________________________________________________________

    What activities do you find the most effective for your learning style in training sessions like these?
    _____________________________________________________________________
    _____________________________________________________________________
    _____________________________________________________________________
    _____________________________________________________________________

  • Building Compact Framework Unit Tests in Microsoft Team Foundation Server with Team Foundation Build

     

    You still can't run compact framework unit tests in Team Foundation Build very easily.  <ShamelessPlug>You'll be able to with TFS Advantage - Compact Framework Edition</ShamelessPlug>  Anyway, you would think you could compile them consistently though, right?

    Well, that's not always the case.  I was helping out Chris Tacke of OpenNETCF with a problem he was having with build failures on solutions that contained:

    • Compact Framework (CF) projects
    • Compact Framework unit test projects
    • MSTest private accessors
    • Were participating in a continuous integration process under Team Foundation Build using Microsoft Team Foundation Server.

    He has had success with all of these technologies independently, but when combined together, it went boom!  You know when a problem mentions four different technologies it's always a fun one to solve. ;-)


    The Setup

    Chris has CF projects, CF unit test assemblies, some private accessors and he submits to the build.  The build fails with "API restriction".

    Here's the error:


    Using "BuildShadowTask" task from assembly "C:\Program Files\MSBuild\Microsoft\VisualStudio\v9.0\TeamTest\Microsoft.VisualStudio.TestTools.BuildShadowsTask.dll".

    Task "BuildShadowTask"

    C:\Program Files\MSBuild\Microsoft\VisualStudio\v9.0\TeamTest\Microsoft.TeamTest.targets(14,5): error : API restriction: The assembly 'file:///C:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\PublicAssemblies\Microsoft.VisualStudio.SmartDevice.UnitTestFramework.dll' has already loaded from a different location. It cannot be loaded from a new location within the same appdomain.

    Done executing task "BuildShadowTask" -- FAILED.

    Done building target "ResolveTestReferences" in project "TestProject1.csproj" -- FAILED.


    What's going on here?  I don't know exactly, but I've got some bits and a workaround.

    The BuildShadowTask is a component used by the Microsoft.TeamTest.targets used to build the private accessor DLL (e.g. myproject_accessor.dll) that a unit test uses to get at private and protected members of a test target.

    It in turn calls the Publicize.exe executable to do the actual work.

    A bit more on Chris Tacke's scenario.  He's taken one of my patterns and created a TestClassBase that does some common initialization, cleanup and provides some test specific helper functions.  This has been put into a CF unit test assembly that has no real unit tests in it.  Since it has no real unit tests in it, it has no private accessors in it either.

    This was essentially the item that triggers the downfall, albeit, he wasn't doing anything really wrong.

    It appears that when MSBuild, BuildShadowsTask and Publicize do their work, they're pulling in some copy/version of Microsoft.VisualStudio.SmartDevices.UnitTestFramework from somewhere else besides where the rest of the MSBuild process is going to get it from.  And, somehow it is being kept in the same AppDomain as the rest of the MSBuild process.  (So, I doubt that it is publicize.exe that's the problem).  Or vice versa, MSBuild is pulling one in and then BuildShadowsTask is attempting too as well.


    The Workaround


    If you are going to use private accessors in any compact framework unit test assembly in your solution, use it in all compact framework unit test assemblies.  Even if you have to refer to something you don't need to make a private accessor.  Even if you create a "shill target" assembly, you need to have in it in all of them.

    Also, we had previously attempted to overcome the inability of Team Build to find the Microsoft.VisualStudio.SmartDevices.UnitTestFramework.dll by registering it in the GAC.  As always, when you mess with fire you get burnt.  At this point, I have had Chris has add the following to his build scripts (update the path as appropriate to find Microsoft.VisualStudio.SmartDevices.UnitTestFramework.dll)

    <ItemGroup>

    <AdditionalReferencePath Include="c:\Program Files\Microsoft Visual Studio 9.0\Common7\IDE\PublicAssemblies\" />

    </ItemGroup>

     

     

  • Code Snippets For Unit Testing (w/Typemock)

    I have uploaded some code snippets to download that use some of my common patterns for unit testing using MSTest.  Some are Typemock centric.  Some depend on helper methods which are unpublished; implement in your own code or delete the references to them.  They're not polished for release by any means, but you may find them useful. 

    Here's a quick list of what's in there.

           <Title>Unit Test For ctor</Title>
          <Shortcut>utc</Shortcut>
          <Description>Code snippet for a ctor unit test.</Description>

          <Title>Property = null</Title>
          <Shortcut>utpn</Shortcut>
          <Description>Code snippet for unit test to test setting a non-nullable property to a null value.</Description>

          <Title>Unit Test A Property</Title>
          <Shortcut>utp</Shortcut>
          <Description>Code snippet for unit test to test a property</Description>

          <Title>Unit Test</Title>
          <Shortcut>utcp</Shortcut>
          <Description>Code snippet for unit test to test a ctor that accepts a value that sets a property.</Description>

          <Title>Property = (argument out of range)</Title>
          <Shortcut>utpiv</Shortcut>
          <Description>Code snippet to unit test setting a property to an invalid value and receiving a ArgumentOutRangeException.</Description>

          <Title>Unit Test a method on a target.</Title>
          <Shortcut>utm</Shortcut>
          <Description>Code snippet to unit test a method on the target.</Description>

          <Title>Typemock Recorder Block</Title>
          <Shortcut>rx</Shortcut>
          <Description>Code snippet for a recorder block for TypeMock</Description>

  • Some keys to success with continuous integration and VSTS

    Third Party Software

    All third party software should be treated as part of the source code.  It needs to be included in the VSTS source code repository using the same relative paths as would be expected on a developer’s machine.  The exception to this is binaries installed in the GAC (which  really is the developer’s enemy, not his friend, but that’s a subject for later).  Additionally, the only way to get the same results everywhere is to use the same version everywhere.  If the developers are using Acme.dll, version 1.2.3.4 on their machines, the version in source control needs to match.  All developers upgrade at the same time.  This will prevent late night tail chasing of a build or test failure.   To accomplish these goals, place all third party software into an appropriate folder in the “thirdparty” directory of any of your VSTS projects.  I typically will place the files there first, then go reference them from my projects.  Using this practice, you avoid the “prototyping” and forgetting to update a path before checking in.  After setting these references, remember to go into the Source Code Explorer and add them to the appropriate place(s).  Include them with your initial check-in of their usage. Most third party software does not require installation, nor registration on a build server to be successful. 

    Unit Testing

    Couple of items of note about writing unit tests.  Unit tests should be automatable, predictable and reproducible.  This means no UI elements popping up in them.  I rarely recommend modifying production code for testing infrastructure needs.  (e.g. exposing a property with a higher than originally intended scope, compiler directives, etc).  MSTest does have some great facilities to get to the innards of a production class without having to actual modifying the production code.  These are the private accessors;  I find these meet 99% of your needs for accessing private members, I chalk the other 1% up to, “oh well, that part won’t be tested as well.”  BTW, when I say not to modify production code to meet your testing infrastructure, I mean only that.  I modify production code daily to make it more testable, but that’s a completely different development activity.  

    Single Directory Compilation

    It takes a little more upfront work, but I recommend (especially for managed assemblies) to adopt a single output folder strategy.  (this might be trickier with unmanaged C++) I do this for a number of reasons:

    • Non referenced (or loosely coupled assemblies) will be available to other assemblies.  In other words, if I have a assembly I build and its pulled into the application at run time, but nothing references directly as a project, it will be there from the last compilation.  This negates a manual copy/paste operation, or monkeying with post build events in the projects.
    • It’s faster – quite simply, if you do this and set “Copy Local = false”, the compiler/operating system doesn’t have to copy and move all of your referenced assemblies around to keep the dependent assemblies up to date.  It builds it into the obj directory, puts a copy into the output, and that’s it.  In a larger solution of 100 projects with tons of references and a large dependency tree, compile times skyrocket.  This mitigates that problem.
    • You always know where your outputs are and can quickly see what is up to date and what’s not.
    • You can do a “hard clean” (Shift-Del) REAL easy.
    • Oh, and it’s the way the build server is going to build your software anyway, so when you look like the build server, the build server becomes your friend, not your enemy.  Some hinky problem that might come up in the build will more than likely produce itself on your box, before you check in. My trick to doing this is to prefix your <OutputPath> value in your project files with the $(SolutionDir)property (macro), and subsequently your project templates (located in a path similar to C:\Users\tim\Documents\Visual Studio 2008\Templates\ProjectTemplates ) to have the following.  This automagically puts into a single directory compilation strategy.  It does NOT set your CopyLocal = false.  

     

    <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> 

    <DebugSymbols>true</DebugSymbols>
    <
    DebugType>full</DebugType>
    <
    Optimize>false</Optimize>
    <OutputPath>$(SolutionDir)\bin\Debug\</OutputPath>
    <
    DefineConstants>DEBUG;TRACE</DefineConstants>
    <
    ErrorReport>prompt</ErrorReport>
    <
    WarningLevel>4</WarningLevel>
    </PropertyGroup>

     

    Monitoring The Build

    Monitor the build after submitting changes, monitor the status.  You can do this using several methods:
    • The build explorer is available from the Team Explorer right in VS.net. 
    • If you install the Team Foundation Server Power Tools (highly recommended), you can run the Build Notification tray app.
    • Project Alerts – will email you the results of every build.  I have an Outlook rule that moves the successful ones to a subfolder and leaves failed builds in my inbox.
    On this note, it is pretty important that you come up with your guidelines on what to do when you have a broken build.  There are many blogs are how people handle them.  My practices (depending on the size of the development team) range from the casual to the tightly controlled.  In smaller groups, usually the developer who’s submission it was and figures it out and gets if fixed in a reasonable amount of time.  When working with large development teams with some reckless developers, I have helped them institute the 3/30 rule, “You get three attempts or 30 minutes.  If not fixed by then, roll it back and get out of the way.”  What is important is that you come up with your own procedures.

     

  • Reinstallation of SQL Server for Team Foundation Server: Error 29015

    I was completing an installation of a single-tier TFS system today.  Another contractor thought he was going to just get it installed with a click-click-next-next.  Anyway, to make a long story shorter, the SQL Server install was completely wrong to meet the TFS needs.  So, my inclination was to re-image the server, but that would not be available until the next day.  Relunctantly, I opted to do an uninstall/reinstall of SQL Server.  I have tried this in the past to no avail.  Today would be different, right?  Yes and no.

     The SQL Server reinstall went pretty good.  I got through 80% of the TFS install when I get this message:  Error 29105.Team Foundation Report Server Configuration: The SQL Reporting Services databases were not created.  Retry?

     

    Someone made the C: drive 2 GB on this server;  I don't know why, but it is.  Has this killed me?  Oh no, six hours of work down the drain, just when I was feeling pretty good!

    Nope.  Turns out, SQL Server leaves the database files in place when you uninstall it.  This makes sense.  The reporting files are still there and the install does not want to overwrite them.

    In my case, I got it install by deleting the following files from the SQL Server data directory.

  • How to find all Assemblies with MSTest test classes in a directory in a single LINQ statement

    I needed a component that would examine a directory and find all test assemblies in a directory.  This sounded like a job for LINQ.

    var allFiles = from fileName in Directory.GetFiles(directory.FullName, "*.dll")
    let assembly = Assembly.LoadFile(fileName)
    let types = assembly.GetExportedTypes()
    from Type t in types
    where t.GetCustomAttributes(typeof(TestClassAttribute), true).Length > 0
    select assembly ;

    The above LINQ query will:

    1. Get all DLL (assemblies) files.
    2. Use the *non-preferred* way to load each of the files as an assembly using Assembly.LoadFile()
    3. Reflect all the public types in the assembly using Assembly.GetExportedTypes()
    4. Retrieve an array of any TestClassAttributes from each type and check to see if there are any
    5. Put the results of into an IEnumerable<Assembly>

    Using this above, in a single statement, I have a managable list of all assemblies in the directory that have a least on MSTest test class in them.

Hound Dog Enterprises, LLC
Powered by Community Server (Non-Commercial Edition), by Telligent Systems