Brad Wilson - The .NET Guy

Technologist. Agile Evangelist. Poker Player. Amateur Neologist. Metalhead.

My Links

Post Categories

Article Categories

Archives

Blog Stats

Stuff

Friday, December 21, 2007 #

THIS BLOG HAS MOVED!

Sorry to have to do this to you, but I've moved blogs. Thanks for those of you who have put up with the occasional outages and the lack of comments (due to spam). The new blog should be stabler.

New blog address: http://bradwilson.typepad.com
New RSS feed: http://feeds.feedburner.com/BradWilson

Eventually I would like to get the content moved over to the new blog, and put redirects in place here. For now, the content will continue to live here so that it doesn't disappear.

Thank you for your patience!

posted @ 4:20 PM

Tuesday, December 18, 2007 #

xUnit.net RC1 Released Today

We (Jim Newkirk and myself) just shipped up the ZIP files for the first (and hopefully only) release candidate for xUnit.net today. This marks the first release where we've split the core of xUnit.net (which is xunit.dll and xunit.console.exe) from the rest of the xUnit.net extensions.

While there is a download available for the xUnit.net RC1 release, you probably want to download the December 2007 Extensions for xUnit.net RC1 release instead. It includes all the bits that are in the xUnit.net RC1 release, plus all the extension bits (such as the TD.NET runner, Resharper runner, etc.).

Our current plan, assuming there is no feedback about major bugs or missing functionality, is to release v1 in January.

What's new in xUnit.net RC1

  • Documentation! We've provided a .chm file with the xUnit.net API documentation, in both the xUnit.net binary download as well as a stand-alone download (for those evaluating xUnit.net).
  • Removed the "static" declaration from the Assert class. This won't change the usage of Assert, but does allow you to derive from Assert to create your own custom assertions.
  • Support static test methods, which makes xUnit.net easily usable from F# (see Harry Pierson's blog post for more information).
  • The console runner now runs in the STA so that xUnit.net can be used for web testing.
  • There are a few more... see the release for more information.

What's new in December 2007 Extensions

  • BREAKING CHANGE! The theory data attributes were renamed from DataViaXxx to XxxData (i.e., DataViaProperty is now called PropertyData). We also added InlineData, which works much like the RowTest attribute from MbUnit. A [Theory] method can have multiple Data attributes associated with it, and they are all utilized.
  • Added AssumeIdentity extension
  • Added FrozenClock extension
  • Added Trace extension
  • Updated to support Resharper 3.1 EAP and x64 machines

posted @ 3:44 PM

Wednesday, December 05, 2007 #

Class "static" Decorator: Unintended Consequences

If a class contains nothing but static members and methods, you can decorate the class with the "static" keyword. The purpose of the keyword is ostensibly as a form of documentation: this class has no instance data or methods, so therefore, you cannot "new" one of them up. Seems like an entirely reasonable thing to do. We did exactly that with the Assert class in xUnit.net.

Unfortunately, it also has two (IMO unnecessary) side-effects: a static class is always sealed, and cannot derive from another class.

What this means is: if you have a static class, it cannot extend, and it cannot be extended. And since the new extension methods feature in C# 3.0 can only add instance methods and not static methods, you're kinda stuck.

Just to be clear, this works fine:

public class StaticBase
{
    public static void This() { }
}

public class StaticDerived : StaticBase
{
    public static void That() { }
}

But this doesn't:

public static class StaticBase
{
    public static void This() { }
}

public static class StaticDerived : StaticBase
{
    public static void That() { }
}

Luckily, we caught this before we released xUnit.net 1.0. We're going to remove the static class decorator from Assert so that you can make your own Assert extensions class. The usage of Assert will not change, since the methods are all still static.

posted @ 7:51 AM

Thursday, November 22, 2007 #

vsvars2008.ps1

If you're an avid PowerShell user like I am, you probably want access to the equivalent of the "vsvars32.bat" that's shipped with Visual Studio. I had a version from 2005, but I don't remember where exactly it came from. I pulled most of it apart to re-work it for Visual Studio 2008, since it required extensive modification.

This version should work on both x86 and x64 systems, and gracefully handles the case where you've decided not to install VC++.

Here it is in its entirety. I put this in a file named "vsvars2008.ps1" which I call from my PowerShell profile.

$VS2008Key = $null

if (test-path HKLM:SOFTWARE\Wow6432Node\Microsoft\VisualStudio\9.0) {
    $VS2008Key = get-itemproperty HKLM:SOFTWARE\Wow6432Node\Microsoft\VisualStudio\9.0
}
else {
    if (test-path HKLM:SOFTWARE\Microsoft\VisualStudio\9.0) {
        $VS2008Key = get-itemproperty HKLM:SOFTWARE\Microsoft\VisualStudio\9.0
    }
}

if ($VS2008Key -ne $null) {
    $vsPath = split-path $VS2008Key.InstallDir -Parent | split-path -Parent
    $vcPath = join-path $vsPath "VC"

    if (test-path $vsPath) {
        write-host "Setting environment for Microsoft Visual Studio 2008."

        # Determine installation directory of Platform SDK

        $WindowsSdkDir = $null

        if (test-path "HKLM:SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows") {
            $WindowsSdkDir = (get-itemproperty "HKLM:SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows").CurrentInstallFolder
        }
        else {
            if (test-path "HKLM:SOFTWARE\Microsoft\Microsoft SDKs\Windows") {
                $WindowsSdkDir = (get-itemproperty "HKLM:SOFTWARE\Microsoft\Microsoft SDKs\Windows").CurrentInstallFolder
            }
            else {
                if (test-path "HKCU:SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows") {
                    $WindowsSdkDir = (get-itemproperty "HKCU:SOFTWARE\Wow6432Node\Microsoft\Microsoft SDKs\Windows").CurrentInstallFolder
                }
                else {
                    if (test-path "HKCU:SOFTWARE\Microsoft\Microsoft SDKs\Windows") {
                        $WindowsSdkDir = (get-itemproperty "HKCU:SOFTWARE\Microsoft\Microsoft SDKs\Windows").CurrentInstallFolder
                    }
                    else {
                        $WindowsSdkDir = join-path $vcPath "PlatformSDK"
                    }
                }
            }
        }

        $FrameworkKey = get-itemproperty HKLM:SOFTWARE\Microsoft\.NETFramework
        $env:FrameworkDir = $FrameworkKey.InstallRoot
        $env:FrameworkVersion = $VS2008Key."CLR Version"
        $env:Framework35Version = "v3.5"

        $env:DevEnvDir = $VS2008Key.InstallDir

        # PATH environment settings

        $paths = @()
        $paths += $env:DevEnvDir
        $paths += join-path $vcPath "BIN"
        $paths += join-path $vsPath "Common7\Tools"
        $paths += join-path $env:FrameworkDir $env:Framework35Version
        $paths += join-path $env:FrameworkDir $env:FrameworkVersion
        $paths += join-path $vcPath "VCPackages"
        if (test-path (join-path $WindowsSdkDir "bin"))
            { $paths += join-path $WindowsSdkDir "bin" }

        $pathText = [string]::Join(";",$paths)
        $env:PATH = $pathText + ";" + $env:PATH

        # INCLUDE environment settings

        $includes = @()

        if (test-path (join-path $vcPath "atlmfc\include"))
            { $includes += join-path $vcPath "atlmfc\include" }
        if (test-path (join-path $vcPath "include"))
            { $includes += join-path $vcPath "include" }
        if (test-path (join-path $WindowsSdkDir "include"))
            { $includes += join-path $WindowsSdkDir "include" }

        if ($includes.Count -gt 0)
        {
            $includeText = [string]::Join(";",$includes)
            $env:INCLUDE = $includeText + ";" + $env:INCLUDE
        }

        # LIB environment settings

        $libs = @()

        if (test-path (join-path $vcPath "atlmfc\lib"))
            { $libs += join-path $vcPath "atlmfc\lib" }
        if (test-path (join-path $vcPath "lib"))
            { $libs += join-path $vcPath "lib" }
        if (test-path (join-path $WindowsSdkDir "lib"))
            { $libs += join-path $WindowsSdkDir "lib" }

        if ($libs.Count -gt 0)
        {
            $libText = [string]::Join(";",$libs)
            $env:LIB = $libText + ";" + $env:LIB
        }

        # LIBPATH environment settings

        $libpaths = @()

        $libpaths += join-path $env:FrameworkDir $env:Framework35Version
        $libpaths += join-path $env:FrameworkDir $env:FrameworkVersion
        if (test-path (join-path $vcPath "atlmfc\lib"))
            { $libpaths += join-path $vcPath "atlmfc\lib" }
        if (test-path (join-path $vcPath "lib"))
            { $libpaths += join-path $vcPath "lib" }
        
        $libpathsText = [string]::Join(";",$libpaths)
        $env:LIBPATH = $libpathsText + ";" + $env:LIBPATH

        $env:VSINSTALLDIR = $vsPath
        $env:VCINSTALLDIR = $vcPath
        $env:WINDOWSSDKDIR = $WindowsSdkDir
    }
    else {
        write-error "Couldn't find the Visual Studio 2008 installation directory."
    }
}

posted @ 10:59 PM

Installing iTunes on x64

There are two known problems with iTunes on x64. Since I paved my home desktop box to Vista x64 this morning, I knew I was going to need to figure out how to get iTunes running: not only does it stream music for me (from my home theater PC in the living room), but it's also my iPhone sync source.

Before you install iTunes, make sure 32-bit VBScript is enabled.

After you install iTunes, you'll need to install the 64-bit Gear drivers. iTunes uses Gear its ripping and burning support, but they only ship x86 drivers in the box; when you launch iTunes on x64 it yells at you about missing services. You can install the x64 Gear drivers from the Gear web site.

I couldn't find both of these pieces of advice in one spot, so I figured I'd save it here, for myself if nobody else. :)

Update: Apparently, iTunes isn't quite fully functional; in 64-bit form, you can't sync an iPhone. This hasn't affected me yet because my music is on my Mac mini, and for contacts and calendar, I sync to a 32-bit VMware VM on my MacBook Pro (let's not even talk about how totally broken the iPhone info-sync appears to be with Entourage).

posted @ 8:47 AM

Sunday, November 11, 2007 #

[FreezeClock] xUnit.net Extension

I've just checked in my [FreezeClock] extension into xUnit.net Extensions project, the source for which is available right now in source form in change set 7544. This is a simplified version of a similar Clock class that we use internally in the CodePlex code itself.

The idea behind [FreezeClock] is simple. Rather than using DateTime.Now, DateTime.UtcNow, or DateTime.Today, instead you use Clock.Now, Clock.UtcNow, and Clock.Today. During normal operation, these Clock operations are just simple forwards on to their DateTime counterparts. (The Clock class is provided as part of the extension, in the XunitExt namespace.)

You can freeze the clock by calling one of Clock's FreezeXxx() methods. Then, until you call Thaw(), all the calls to Clock.Now, Clock.UtcNow, and Clock.Local will use the frozen values. The reason here is for testing purposes: when you have a frozen and consistent time, it makes comparisons against expected values much simpler, because you don't have an introduce "slop" into the comparison to take into the account the execution time of the test code.

In addition to the Clock class, the extension introduces an AOP-style before/after attribute that you can apply to your tests to automatically freeze and thaw the clock for you. For example:

[Fact, FreezeClock]
public void FrozenWithCurrentTime()
{
    DateTime result1 = Clock.Now;
    Thread.Sleep(100);
    DateTime result2 = Clock.Now;
 
    Assert.Equal(result1, result2);
}

Don't forget that the implications of date/time management also extend beyond your code. For example, when using this system, if you need to test dates & times that are placed into your database that are based on the current date & time, those values need to come from your .NET code (specifically, calling Clock.Now and friends) rather than using the date/time functions built into your database to populate those field values.

Make sure to check out all the unit and acceptance tests to see how the classes work. For further discussion, please visit the corresponding Forum Post.

posted @ 10:56 AM

Call for Presentations: Agile 2008

Mitch has posted the Call for Presentations for Agile 2008 in Toronto next summer.

I went to Agile 2006, mostly because I was presenting (and there, mostly because Mitch came in at the 11th hour and shepherded the process along). While I sincerely enjoyed presenting, many of us lamented that something seemed to be missing from the conference. Peter summed it up best by saying that the soul -- the Zen -- of agility seemed to be missing. Everybody was talking about the mechanics, but nobody was talking about the organics.

I didn't go to Agile 2007, partly because of that and partly because I was "saving" up my big trip for the PDC that never materialized. I'm thinking about trying to create a talk about agile philosophy for this year, but I'm not quite sure what I want to say. This blog post by Jonathan Edwards about Beautiful Code has been stewing in my brain for several months now...

posted @ 8:58 AM

Saturday, November 10, 2007 #

Calling All xUnit.net Extenders!

We're rapidly approaching the point where we want to finalize what's going into the 1.0 version of xUnit.net.

I know we made lots of big changes from Beta 1 to Beta 2. We felt like these changes, while somewhat disrupting, provided a better foundation for xUnit.net going forward. We're not planning any more big sweeping changes; our feature & issue list for the proposed Release Candidate 1 is still relatively small.

You may have also noticed that we removed much of the source code from the xUnit.net project itself. All that remains is the source to xunit.dll and xunit.console.exe (and the associated unit tests). The rest of the source code -- including the TestDriven.NET and Resharper runners -- has been moved to the xUnit.net Extensions project. The Extensions project will issue releases at the same time as the xUnit project, with the first release being extensions suitable for use with RC1.

By keeping a tight core with well-defined and well-used extension points, we're hoping that releases of xUnit.net itself will be very infrequent; ideally, we release 1.0 and never have to release again. Ideally. :)

We believe that most of the activity will move to the xUnit.net Extensions project, hopefully with many community contributions, both inside and outside of Microsoft. Yes, we are planning to accept community contributions!

The call to action today, then, is two-fold.

First, if you think there are any missing features and/or outstanding bugs in the core of xUnit.net itself (that is, in xunit.dll and the console runner xunit.console.exe), now is the time to speak up. If you haven't already, please start using Beta 2 and let us know what's missing from the core.

Second, there is an open issue for the Release Candidate titled Flesh out ITypeInfo, IMethodInfo, IAttributeInfo. These three interfaces are used within the runner infrastructure to determine which classes contain tests, which methods are tests, and which attributes they are decorated with.

These interfaces aren't nearly as full featured as their reflection counterparts. They contain just enough information for the xUnit.net runner infrastructure to be able to inspect and run our own test types (plus our NUnit extension, [RunWithNUnit]). Since these interfaces are defined in the core xunit.dll library, we'd like to know which things are missing from them that would be required by extenders.

Specifically:

  • People implementing ITestClassCommand (for [RunWith()] support) will likely be using all three
  • People implementing custom test types (deriving from [Fact] and/or implementing ITestCommand) will likely be using IMethodInfo and IAttributeInfo

If you're planning to do either of these activities, we'd love for feedback on these interfaces.

For existing implementations of these interfaces, there is a reflection wrapper inside of xunit.csproj (in Reflector.cs) and several Resharper wrappers in xunitext.runner.jetbrains.csproj (in TypeWrapper.cs, MethodWrapper.cs, and AttributeWrapper.cs).

If you have feedback on anything regarding the xUnit.net 1.0 RC1, and especially around these three interfaces, please use the xUnit.net forums for discussions. If you need to contact me directly, please use my CodePlex Contact Page.

Thanks, and happy extending!

posted @ 9:44 AM

Friday, November 09, 2007 #

On To New Things

One of the great things about working at Microsoft is that there is a culture of career growth which encourages you to look for new opportunities when you're ready. One of the worst things about most of the places I've worked is having to keep "secret" when you're looking to make a change.

I've been at CodePlex nearly 18 months now, and I think we've been a big success since we launched in May 2006. I've heard many people tell me that CodePlex changed their opinions about Microsoft, Open Source software, and community-driven software development. You can't ask for more than to be a part of that kind of impact. Not only did I get to help build a great service, I also got to work on a source control client, a dependency injection system, and a unit testing framework, the latter two in my 20% Slack time. It's been a tremendously good time with some incredibly smart people.

Eventually, though, I get an itch to try new things and meet new people. I'm scratching that itch by joining the officelabs team. There hasn't been a lot of talk about officelabs in the public yet, so I'll let the text from one of our job openings say it:

Officelabs is a new group in Microsoft Business Division tasked to accelerate productivity innovation at Microsoft by doing real-code prototyping and customer based concept testing. We are not limiting our innovation in current Office applications related areas. Our scope is any productivity related application, web services, mobile solutions, etc. We target on ‘productivity’ broadly defined-at work, home, and school.

We are assembling small teams of top notch developers to experiment with the most creative ideas that offer great values to customers and demonstrate high level of thought leadership. Team members self organize into project teams to implement the ideas using agile development process. We have small size project teams with 2-3 devs. The teams are self managing and are empowered to make all project related decisions, including scope, direction, architecture, technology choice, schedule, direct customer/partner interaction, etc. We promote shared source development to leverage the tremendous developer talent across Microsoft. We deliver the ideas with high quality for both internal and external trials.

I'll be moving to officelabs at the end of November.

posted @ 1:47 AM

Sunday, October 28, 2007 #

Seattle Nerd Dinner: November 8

Scott Hanselman is planning the next Seattle Nerd Dinner for the evening of November 8. I won't be able to make this one, since that's the day of my surgery, but the last one was good. :)

posted @ 5:49 PM