Apparently I'm in tester mode these days. Today I spent the entire day figuring out how to do proper unit testing with Visual Studio 2005's new Test System. It's integrated with the Visual Studio Team Edition, which my client is using for a variety of small teams where every developer plays just about every role. Here's a quick overview of the unit testing features and a webcast of some MS dudes pitching test-driven development (TDD) in VS 2005 (more on that soon).
The big buggaboo that consumed my day is the little fact that when a test is executed, the app doesn't run in the bin\Debug directory like normal, but rather in the ~\Local Settings\Application Data\VSEqtDeploymentRoot where ~ is the user's home directory, generally under C:\Documents and Settings\<user name>. You can change that test run path in VS, but you won't want to point it to your solution folder because it copies all the runtime assemblies into a temp folder there. Sure, it sounds like a good thing to isolate your tests, but what about config files???
Now, I already had unit tests built for NUnit and found this crafty tool to do conversions. But I didn't use it since there were just a few tests so far and I wanted to ingrain all the differences in my fragile little mind. However, right off the bat I realized that you can't just convert any ole' class library into a VS test library. First, you have to create a test project from scratch, and then write tests or copy your existing ones in. (The instructions on the tool just mentioned indicated the same thing.) I spent a good while trying to hack the solution and project files to no avail.
Also, in my June or July release of VS 2005, you can't just select Add > New Test from the solution's context menu, either, because it will create a VB.Net project <blech> (unless that's what you really want, of course). Instead you have to choose Test > New Test from the main menu to get a choice of languages and the option to use the Unit Test Wizard. The wizard works after you get past it's penchant for reverting back to VB. I accidentally create a VB test project despite my initial choice of C# and had to delete and re-create, so doulbe check! It would have been a pain if under source control instead of in my SandBox solution.
So, I finally got a C# test project, copied my NUnit test into it, and made the minor syntax changes to attribution (TestFixture becomes TestClass, Setup becomes TestInitialize, TearDown becomes TestCleanup, and Test become TestMethod - I like these better). I ran the tests using TestDriven.net's handy context menu option and everything worked. Then I got ambitious. Let's use the built in test execution method like they did in the wabcast!
It's actually pretty simple: you just set the test project as the startup project, and run it (F5). Hmmmm....but every test broke. And I just ran them with TestDriven.net! What gives?
The cool thing about running tests with the Test Manager built into the IDE is that they run in Debug mode (or whatever your configuration setting is). That means you can click a break-point, run, and inspect your variables. For me, that inspection showed that no AppSettings were being retrieved properly. I soon discovered that tests were running in a whole new place, as previously stated. The DLLs were being copied, but .config files weren't. Hmmm...what to do? To shorten an already long story.... I eventual found this one single beautiful blog post about copying config files in regard to NUnit and TestDriven.net. Thank you Loren Halvorson!
So here's the deal:
- In each test project, create an App.config file with your AppSettings you'd normally put in Web.config or your main executable's config file.
- In your test project's properties pane, select Build Event and add this line to your post-build command line: copy /Y $(ProjectDir)app.config $(TargetPath).config
- Run your tests (F5).
- See the pretty status list and the red and green result indicators. Yay!
My colleauge and I spent quite a bit of time trying to make this config-copying work for other class libraries. No dice. The build-event will run on other projects, but the VS Test System will only copy the contents of the bin\Debug directory for the selected test project to the test environment, not any config files from pre-requisite projects.
The down-side having an App.config for each test project is that AppSettings now have to be maintained in multiple config files. While hunting for solutions we came across a post by Paul Wilson about including AppSettings from one config file to another. However, since other config files from other projects don't get copied to the test path, you lose your relative path to them and the inclusion breaks. Also, only <appSettings/> has a "file" attribute, not <connectionStrings/> as is now en vogue. You have to put everything in every config file, and you get to use the new ConfigurationManager in all of it's glory. Be sure to add the System.Configuration.dll reference to your project!