Tuesday, May 22, 2007

VS2005 Item Templates

I've been spending a lot of time lately coding unit tests. If I were writing tests for a class named Chainsaw, I would start with a blank class file, and modify til it looks something like this:

using System;
using System.Collections.Generic;
using System.Text;
using NUnit.Framework;
using Pedro.PowerTools;
 
namespace Pedro.PowerTools.UnitTests
{
    [TestFixture]
    public class ChainsawUnitTests
    {
        ChainsawAdapter myAdapter;
 
        [TestFixtureSetUp]
        public void FixtureSetUp()
        {
            myAdapter = new ChainsawAdapter();
        }
    }
}

If you were to compare all of the TestFixtures in the assembly, you would find:
  1. For the most part, I have the same 'using' statements in each
  2. They all have the same namespace
  3. The class name for each TestFixture is the class to test, followed by "UnitTests"
  4. The data adapter name is the class to test, followed by "Adapter"

*Note - Yes, I'm testing several layers at once. Call it efficient. Call it lazy. It's simply my preference.

Though this isn't difficult to create by hand, there's an easier way - Item Templates. What I want is a way to right-click on my Project, choose Add > New Item, pick "MyUnitTests" from the list, and have it magically create the basic code. Turns out it's quite simple.

Start by placing the above code in a .cs file. Choose File > Export Template... from the menu. In the Choose Template Type screen, select "Item template" and the project where the .cs file exists.


Click Next. In the Select Item To Export screen, check the box beside the .cs file (ChainsawUnitTests.cs in my case.)


Click Next. Under Select Item References, check the box for nunit.framework. Ignore the warning.


Click Next. On the Select Template Options screen, enter the Template name and description. Make sure the box to "Display an explorer window..." is checked, and click Finish.


Once the template is generated, it will be placed in a .zip with the name of the template (for me, this is MyUnitTests.zip.) This is a decent start, but we need to modify a few things.

Open the .zip, and you should see the following files:
  • _TemplateIcon.ico
  • ChainsawUnitTests.cs
  • MyTemplate.vstemplate

Open MyTemplate.vstemplate. Near the end of the file, you should see the following <ProjectItem>

<ProjectItem SubType="Code" TargetFileName="$fileinputname$.cs" ReplaceParameters="true">ChainsawUnitTests.cs</ProjectItem>

In VS2005, when you choose to create a new item for a project, it asks for a filename. This filename, minus the extension, is placed in $fileinputname$. For this template, however, I want to type in the class to test, and have it generate a filename using the classname, followed by "UnitTests.cs". So let's change the line to

<ProjectItem SubType="Code" TargetFileName="$fileinputname$UnitTests.cs" ReplaceParameters="true">ChainsawUnitTests.cs</ProjectItem>

Save the file, and let's open ChainsawUnitTests.cs. It looks nearly identical to the original

namespace $rootnamespace$
{
    [TestFixture]
    public class $safeitemname$
    {
        ChainsawAdapter myAdapter;
 
        [TestFixtureSetUp]
        public void FixtureSetUp()
        {
            myAdapter = new ChainsawAdapter();
        }
    }
}

In fact, the only changes made were to the namespace and classname. Earlier, I mentioned wanting to type in the class to be tested, as opposed to the unit test class, when adding an item through the wizard. This is because I want to replace "Chainsaw" in each instance of "ChainsawAdapter" with the class I'm testing. As you may have already guessed, this comes from $fileinputname$. Two replacements and we have the following:

using System;
using System.Collections.Generic;
using System.Text;
using NUnit.Framework;
using Pedro.PowerTools;
 
namespace $rootnamespace$
{
    [TestFixture]
    public class $safeitemname$
    {
        $fileinputname$Adapter myAdapter;
 
        [TestFixtureSetUp]
        public void FixtureSetUp()
        {
            myAdapter = new $fileinputname$Adapter();
        }
    }
}

Save the changes and re-zip the files. Drop the .zip in your custom ItemTemplates folder (the location can be found and/or modified in the VS Options dialog, under "Projects and Solutions" > "General." Having done all that, go back to the test project in VS. Right-click on the project and choose Add > New Item. In the Templates dialog, you should see your new template near the bottom of the dialog. Enter "DrillPress.cs" into the Name textbox and click Add.

Assuming all went well, VS should generate DrillPressUnitTests.cs with the following content:

using System;
using System.Collections.Generic;
using System.Text;
using NUnit.Framework;
 
namespace test1
{
    [TestFixture]
    public class DrillPressUnitTests
    {
        DrillPressAdapter myAdapter;
 
        [TestFixtureSetUp]
        public void FixtureSetUp()
        {
            myAdapter = new DrillPressAdapter();
        }
    }
}

Friday, May 18, 2007

Reducing the size of ccnet.config

[Update 5/19/09: The latest version of CCNet makes this much easier by using a Configuration Preprocessor. I have a short writeup here.]

My demo setup only contains two projects, and there are already a few items that have been duplicated. Items such as paths to SourceSafe and MSBuild executables. As you add more projects, you find yourself copying and pasting lots of info. This isn't recommended when writing code, so why should a config be any different?

Let's take a look at the sourcecontrol blocks. First, my still-empty custom tasks project


<sourcecontrol type="vss" autoGetSource="true">
<ssdir>c:\vss</ssdir>
<executable>C:\Program Files\Microsoft Visual SourceSafe\ss.exe</executable>
<project>$/MSBuild.Chainsaw.Tasks</project>
<workingDirectory>MSBuild.Chainsaw.Tasks</workingDirectory>
</sourcecontrol>

Then the MSBuild Community Tasks


<sourcecontrol type="vss" autoGetSource="true">
<ssdir>c:\vss</ssdir>
<executable>C:\Program Files\Microsoft Visual SourceSafe\ss.exe</executable>
<project>$/MSBuild.Community.Tasks</project>
<workingDirectory>MSBuild.Community.Tasks</workingDirectory>
</sourcecontrol>

Both <ssdir> and <executable> are identical. To simplify things, add the following to the top of the config (above the opening <cruisecontrol>)


<!DOCTYPE cruisecontrol [
<!ENTITY ssCommon
"
<ssdir>c:\vss</ssdir>
<executable>C:\Program Files\Microsoft Visual SourceSafe\ss.exe</executable>

">
]>

Now, those sections can be replaced with "&ssCommon;", like so


<sourcecontrol type="vss" autoGetSource="true">
&ssCommon;
<project>$/MSBuild.Chainsaw.Tasks</project>
<workingDirectory>MSBuild.Chainsaw.Tasks</workingDirectory>
</sourcecontrol>

Adding FxCop to the build

Most (though certainly not all) developers agree that code reviews are a useful step in the development process. I won't go into specific benefits, as there are numerous writings on the subject.

One of the downsides, however, is that code reviews take time. In fact, you could spend more time reviewing the code than you did writing it. This is where FxCop can help. Though it won't catch problems with things like business rules, it does flag various issues related to performance, security, and code consistency/maintainability. By adding it to the build, we get a decent code review with every checkin.

For this demo, I downloaded the source for the MSBuild Community Tasks. Dropping this into SourceSafe, I set up a new project in CruiseControl.Net.


<project name="MSBuild.Community.Tasks">
<sourcecontrol type="vss" autoGetSource="true">
<ssdir>c:\vss</ssdir>
<executable>C:\Program Files\Microsoft Visual SourceSafe\ss.exe</executable>
<project>$/MSBuild.Community.Tasks</project>
<workingDirectory>MSBuild.Community.Tasks</workingDirectory>
</sourcecontrol>
<tasks>
<msbuild>
<executable>c:\winnt\Microsoft.Net\Framework\v2.0.50727\msbuild.exe</executable>
<projectFile>MSBuild.Community.Tasks\Source\MSBuild.Community.Tasks.sln</projectFile>
<buildArgs>/noconsolelogger </buildArgs>
<logger>c:\ThoughtWorks.CruiseControl.MsBuild.dll</logger>
</msbuild>
</tasks>
<publishers>
<statistics/>
<xmllogger/>
</publishers>
</project>


To add FxCop, we first need to create a project file. Start FxCop. From the menu, choose File > Save Project. Out of laziness, I saved the file as c:\DefaultRules.FxCop. Now to update the build file. Below the <msbuild> section, add the following


<exec>
<executable>C:\Program Files\Microsoft FxCop 1.35\FxCopCmd.exe</executable>
<buildArgs>/project:"C:\DefaultRules.FxCop" /fo /q /searchgac /file:"%CCNetWorkingDirectory%\MSBuild.Community.Tasks\Source\MSBuild.Community.Tasks\bin\Debug\MSBuild.Community.Tasks.dll" /out:FxCopLog.xml</buildArgs>
</exec>

Within the <publishers> section, add


<merge>
<files>
<file>FxCopLog.xml</file>
</files>
</merge>

Save these changes and force a build - which fails. Looking at the project report, it looks like everything should have worked. We even have FxCop information on the page. The Build Log, however, notes the missing dependency Microsoft.VisualStuido.SourceSafe.Interop. The assembly isn't being copied to the build output folder.

To fix, open the .sln in VisualStudio. Under the project's References, select the missing interop and set the Copy Local property to True. Checkin the modified project and you should see a successful build.

Now we have FxCop info displaying on the Build Report. We also have a detailed FxCop Report we can access from the Dashboard's menu. Which is all well and good, but the reports aren't the most useful.





Fortunately, you can download alternative stylesheets from the Thoughtworks site. Unzip fxcop-summary.xsl and FxCopReport.xsl, and place in \webdashboard\xsl\ under the cc.net install directory. Open FxCopReport.xsl in your favorite xml editor. Replace all instances of

src="images/

with

src="/ccnet/images/

With the new reports in place, reload the dashboard. If all goes as planned, you should see slightly improved FxCop reports. Note these still aren't perfect, and there are likely others available on the web.



Monday, May 7, 2007

Continuous Integration = Consistently Compileable Code

*Note: This is a continuation of my previous post

"Now that we have basic SS usage defined, where does CC.Net fit into the picture?" Simple - it's what makes sure the code is in a usable state at all times.

Let's say you've finished creating the xml logger and checked everything in. But say you forget to check in one file. Everything builds on your machine, so you don't see the problem. You're pulled from the project and another dev comes in later to continue. Only, when he gets latest and attempts a compile, he receives a number of build errors. Now he wastes time tracking down the cause of the problem - a missing or outdated file - and who might have that file. Maybe you have the file, and he's wasted fifteen minutes. But say you no longer have that file. Now your colleague wasted that time, only to find out someone will have to recreate the work.

Say instead you are working on code at the same time as another dev. His job is to create the data and business layers, while you focus on the front end. Somewhere during development, your colleague decides to modify a few method signatures. Methods that you happen to be using. And your colleague fails to warn you. At some point you'll get latest, only to find that you can no longer compile your code. It's likely that both of you must stop what you are working on and get the build back into a good state. If there are only two of you, it might take twenty minutes. As the number of devs on a project increases, the time required to restabilize the code likewise increases.

I previously worked on a project that had over a dozen developers. Due somewhat to poor architecture, a break anywhere caused problems for the entire team. The choices were to get latest and spend the morning stabilizing the build, or using outdated code, which meant integration later became even more difficult.

Fortunately, these problems are easy to address using CruiseControl.Net. Its job is to monitor the source code repository for any changes. As soon as a change is made, CC.Net gets latest and rebuilds the code. If the compile fails, everyone on the team is immediately (within a few minutes anyway) notified of the failure. The dev who checked in the broken code can address the problem, and other team members know not to get latest for the moment.

Regarding a broken build - if you aren't working on a fix, stay away from the repository. Getting latest means the code on your box will no longer compile. Checking in code may make things worse. It's best to fix one build break before possibly introducing another.

One more thing - if you break the build, fixing it should be your top priority. If you check in code at the end of the day, hang around to verify the build is still good. If you're in a hurry and can't wait for the build, don't check in the code. You're more likely to forget something in your haste, increasing the odds of a break.

Thursday, May 3, 2007

Source Code Control 101

At work, we're moving toward a more standardized development process. Part of that standardization is on the usage of SourceSafe for source code control, and CruiseControl.Net for continuous integration (CI.) The developers on the team come from a variety of backgrounds, and have different levels of experience with CI. As the resident Build Guy, I've spent the most time with the tools and decided to lay out my thoughts on the process.

*Note that these are not the only tools available, and with SourceSafe in particular there are certainly better options. These are simply the tools we are working with.

*Note also that I intended to cover both SS and CC.Net in a single post. It ended up a bit longer than expected, so I'm splitting it into two entries. This post is limited to source code control. The next will dig into continuous integration.

SourceSafe as version control

SourceSafe is not merely a way to back up code in case of hard drive failure. It is a way to revision your code. It allows you to define checkpoints in completed work. It provides an easy way to compare changes and roll back work if you find yourself going down the wrong path.

For example, let's say you're updating a desktop application. The current app generates a text file as output. The goals for the next release are to enhance the logging and to generate xml instead of plain text. To start, you decide to replace the existing log with xml. Looking at the code, you realize the log messages are scattered throughout the entire app. Unless each message is to be a self-contained element, this makes it difficult to generate well-formed xml.

So you begin by creating a custom logger class. This lets you track where in the xml tree you are, and ensures the output is well-formed. After you've finished testing the logger, it's time to replace all of the old logging code with calls to the new class. Right?

Not just yet. Now that you have working code it needs to be checked into SourceSafe. "It doesn't do anything yet," you say? True. However, even though the class isn't used, it's still a functioning piece of code. If you have to switch projects now, you know you can come back later and pick up with a working app.

"What if you need to make a bug fix and release to production?" The code isn't being used, remember? So there shouldn't be an issue.

With the logger checked into SourceSafe, it's time to replace the existing logging code. At the start, everything seems fine. But several hours into the process, you realize something. It appears there's a bit of rarely-used code that logs info in a non-trivial, non-standard way. No problem - you can update the xml logger to deal with the new info. A few changes, which you of course check into SS, and you're back to replacing code. But shortly thereafter, for whatever reason, you realize the logger changes shouldn't have been made. Now what?

Fortunately, the previous revision exists in SourceSafe. It's easy to roll back the code and continue with your work. But say you hadn't checked in the changes? Instead, you would have had to manually modify the code until you were back to the point you were before. If you've ever tried this, you know it's not often a trivial matter. It certainly takes longer than the minute or two required for a SourceSafe rollback.

SourceSafe allows collaboration

Most software projects involve several team members contributing code. This requires some means of getting updated code to the other developers. It may also require a new developer to come in and pick up where another left off.

Going back to the xml logger, say you have the logger code checked in and are pulled off to work on another project. A new developer comes in and is tasked with replacing the old log code. All the new guy has to do is get latest from SS and he can continue right where you left off. Or maybe he comes in at the point where you've added to the logger (just before you realized those changes weren't necessary.) Once the new guy figures out what's going on, it's as easy for him to roll back the code as it would have been for you. There's a clear snapshot of where the code was before the change.

Checkin frequency

So you now see a few benefits of source code control. The next question you may have is "How often do I check in my code?" It depends on what you are doing, but the general answer is "Often." A few times a week is typical, and multiple times a day is entirely possible. The key is to find stopping points throughout the project.

Say you start coding a new multi-tiered application. You begin by writing a few classes in the data layer, making sure you can connect to the database. As soon as you have these compiling and running correctly, check the code in. As you add new classes, check them in. There's no reason to wait until the entire layer is code complete.

Say instead you are working on a desktop application. You begin by placing a few controls on a blank form. Maybe you hook those controls to business logic. Or maybe you prefer to setup the layout before making the code do anything useful. Either way, each piece of logic and each set of controls define a discrete unit of work. Hook up a couple buttons and check the code in. Add logic to traverse the local hard drive, then check the code in. With a bit of practice, you should recognize several good checkin opportunities on any given day. That's not to say you need to check code in this often, but once a day is certainly possible.

One final thought - before checking in the code, make sure it compiles and runs on your box. Checking in code that doesn't compile only hinders development. I'll cover this next time when I introduce continuous integration using CruiseControl.Net.