Unit Testing against the Team Foundation Server 2012 API

Audience

Everyone

I have been working a lot recently with the new Team Foundation Service (TFS Preview) that Microsoft is providing in Azure. I was building an application called TFS Field Annotate that allows you to spelunk a fields changes. One of the problems I ran into is how to Unit Test this. I have been doing a lot of work in Test Driven Development (TDD) recently and after running a Bowling Kata (thanks David Starr) for the last month I don’t want to work any other way.

Updated 2012-04-02 – Patrick Carnahan fixed my code below to work with TFS 11 on both local and build server environments.

This brings us back to the purpose here. Lets take a standard API call to TFS:

TfsTeamProjectCollection collection =new TfsTeamProjectCollection(new Uri("https://mrhinsh.tfspreview.com/DefaultCollection"));
collection.Authenticate();

Figure: Simply connect to TFS

Before the cloud we had 3 options for authentication:

  1. Run the code/application as a user with permission
  2. Add the credentials to the credential store
  3. Pass in explicit credentials to use

While this was just fine, what do you do in the cloud world where authentication was done using Windows Live ID. What do you do if you want to run a service, like the TFS Integration Platform, unattended? Well, up until now we had to log onto that unattended server and re-jig our Live credentials every two days when it expired.

Now while this is OK, but not ideal, for a while what about things like Build Servers running locally and connecting to the cloud or even just something as simple as writing Unit Tests that test an application you are building against TFS Service.

This happened to me the other day while I was working on the TFS Field Annotator that I was building.  I was trying to add some Unit Tests and I was running into authentication issues.

note: I know I am supped to ad my Tests first, but I am not quire there yet.

note: I am also aware that these are “Integration Tests” and not pure “Unit Test”

The authentication issues stemmed from the code above in the automated running scenario and resulted in and error…

image
Figure: TF30064: You are not authorized to access the server

So, why do I get this error when I am in a Unit Test and not connecting through the custom UI.  Well, in the UI the user is specifically selecting the Collection using the TeamProjectPicker dialog. This dialog does all of the Live ID authentication for us so if the user ticks the “remember me” box they don’t have to log in next time.

SNAGHTML1718e02a
Figure: the UI authenticated us

That bring us back to the problem at hand. The UI is not involved with the Unit Tests. In fact I have abstracted the logic for the TeamProjectPicker into a collection selector interface so that I can run the Unit Tests without having the UI popup ever time I run them…

namespace TfsWitAnnotateField.UI.Infra
{
    public interface ICollectionSelector
    {
        TfsTeamProjectCollection SelectCollection();
    }
}

Figure: An Interface to abstract the UI work

Having this interface lets me have two implementation of a concrete class.

  1. CollectionSelector – With the call to TeamProjectPicker UI

    namespace TfsWitAnnotateField.UI.Infra
    {
        class CollectionSelector : ICollectionSelector
        {
            public TfsTeamProjectCollection SelectCollection()
            {
                using (TeamProjectPicker tpp = new TeamProjectPicker(TeamProjectPickerMode.NoProject, false))
                {
                    DialogResult result = tpp.ShowDialog();
                    if (result == DialogResult.OK)
                    {
                        return tpp.SelectedTeamProjectCollection;
                    }
                    return null;
                }
            }
        }
    }

    Figure: Calling the TeamProjectPicker

  2. MockCollectionSelector – With an explicit Collection to tests against and no UI

    namespace TfsWitAnnotateField.UI.Tests
    {
        class MockCollectionSelector : ICollectionSelector
        {
            public TfsTeamProjectCollection SelectCollection()
            {
                return new TfsTeamProjectCollection(new Uri("https://mrhinsh.tfspreview.com/"));
            }
        }
    }
    

    Figure: Calling TfsTeamProjectCollection explicitly

Now here in #2 we have a problem. How do we authenticate?

The only way to do so up until now was to save your Live ID credentials in the Windows Credential Store, but they would only last for 2 days before they expired.

So what happens on the build server?

I would have to log onto the build serve every 2 days and reset the credentials, and my only notification would be that my tests started failing, and thus my builds. Not a good thing.

In a self-hosted TFS instance I can just create some AD credentials and hard code (or put them in a config) them. But in the Hosted Build Service world I have no such option. I don’t even know where my build server is, let alone logging onto it. So the lovely folks on the product team, encountering the same problem themselves, came up with a solution.

You can connect to your TFS Preview instance as an Administrator and load a set of service credentials that you can use to connect unattended.

IAccessControlService acs = _SelectedTeamProjectCollection.GetService();
ServiceIdentity defaultServiceIdentity = acs.ProvisionServiceIdentity();
// Save these values off to use for non-interactive login
Username = defaultServiceIdentity.IdentityInfo.Name;
Password = defaultServiceIdentity.IdentityInfo.Password;

Figure: Retrieving a non-interactive login for your TFS Preview service

Now, it would be a pain in the ass to have to spin up this code all of the time, so I created the TFS Service Credential Viewer that will do the heavy lifting for you.

SNAGHTML172e4063
Figure: We can load out credentials from the remote instance

Now I can copy and past them into my MockCollectionSelector to allow it to connect unattended.

namespace TfsWitAnnotateField.UI.Tests
{
    class MockCollectionSelector : ICollectionSelector
    {
        public TfsTeamProjectCollection SelectCollection()
        {
            // This is constructed with the userName and password from the previous code block
            ServiceIdentityCredentialsProvider provider = new ServiceIdentityCredentialsProvider("Account Service (XXXXXX)", "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");
            return new TfsTeamProjectCollection(new Uri("https://mrhinsh.tfspreview.com/DefaultCollection"), provider);
        }
    }
}

Figure: CollectionSelector for TFS 2010

namespace TfsWitAnnotateField.UI.Tests
{
    class MockCollectionSelector : ICollectionSelector
    {
        public TfsTeamProjectCollection SelectCollection()
        {
            return new TfsTeamProjectCollection(new Uri("https://mrhinsh.tfspreview.com/"), new TfsClientCredentials(new SimpleWebTokenCredential("", "")));
        }
    }
}

Figure: CollectionSelector for TFS 2012

Now that I have my credentials I can run my tests again…

image
Figure: Green, all of my tests are now passing

Woot, they all pass… now to write some more.

Conclusion

If you are using a Behaviour Driven Development (BDD) framework to tests your scenarios (SpecFlow works well with Visual Studio 2012) then you will need to load your service credentials so that we can test without having a user enter credentials…

Upcoming Training Opportunities

These are the next five classes we have, and you can check out our full public schedule of classes.

Timezone:
Live Virtual Professional Scrum Master Online on 29th May 2023
Virtual
29 May-1 May, 2023
09:30-13:30 BST
4 half-days
Live Virtual Professional Scrum Product Owner online 5th June 2023
Virtual
5-8 Jun, 2023
09:30-13:30 BST
4 half-days
Live Virtual PAL Evidence-Based Management Online on 19th June 2023
Virtual
19-20 Jun, 2023
09:00-13:00 BST
2 half-days
APS 19th June 2023
Virtual
19-22 Jun, 2023
09:00-13:00 EDT
4 half-days

We can deliver any of our courses as private in-house training over Microsoft Teams & Mural. We also recommend training based on your accountabilities or role, you can go directly to recommended courses for Scrum MastersProduct OwnersDevelopers and Agile Leaders.

Create a conversation around this article

Share on Facebook
Share on Twitter
Share on Linkdin

Related Courses

No items found

Read more

Martin Hinshelwood nkdAgility.com
https://youtu.be/_fFs-0GL1CA Why do you encourage people to follow a certification path in their career journey? I would encourage you to follow a scrum certification path for the same reason that people go to university. The same reason that people do any course or certification. It gets you a foot in …
Martin Hinshelwood nkdAgility.com
https://youtu.be/QGXlCm_B5zA What will you learn on the PSM II course? There are two main things that most scrum masters will learn on the PSM II or Advanced Professional Scrum Master course. That they haven’t been working effectively as a scrum master to date. That they are there to empower and …
Martin Hinshelwood nkdAgility.com
In Scrum Events across the world, I hear repeated the phrase “that’s how agile works” when describing behaviours that are both unprofessional and the very opposite of an agile mindset. These behaviours will inhibit agility and are a result of a lack of understanding of the underlying principles. We need …
Martin Hinshelwood nkdAgility.com
https://youtu.be/klBiNFvxuy0 What is the most common Aha moment people have in a scrum course? It depends on the scrum course they are attending. The content presented in the Applying Professional Scrum (APS) course leads to very different epiphanies when compared to the content presented on an Advanced Professional Scrum Master …

OUR TEAM

We believe that every company deserves high quality software delivered on a regular cadence that meets its customers needs. Our goal is to help you reduce your cycle time, improve your time to market, and minimise any organisational friction in achieving your goals.

naked Agility Limited is a professional company that offers training, coaching, mentoring, and facilitation to help people and teams evolve, integrate, and continuously improve.

We recognise the positive impact that a happy AND motivated workforce, that has purpose, has on client experience. We help change mindsets towards a people-first culture where everyone encourages others to learn and grow. The resulting divergent thinking leads to many different ideas and opportunities for the success of the organisation.