Previously I’ve posted about how to override the Team Build defaulting productivity directory machinate and produce something a bit more sane.
Unfortunately if you do implement this it can break the built-in test run task, and most of the recipes related to it. You’ll get the following error in your build logs:
MSBUILD : warning MSB6003: The specified task executable "MSTest.exe" may possibly not be run. The directory name is invalid
If you run the build with /verbosity:detailed to see the actual args passed to MSTest.exe, and then run MSTest yourself interactively, you’ll see the real underlying error:
Directory "(my build path)\Binaries\Debug" not found.
For switch syntax, type "MSTest /help"
The problem here is that (as detailed on the TestToolsTask doco) the team foundation build targets sets up MSTest.exe with SearchPathRoot="$(OutDir)", ie $(BinariesRoot)$(Configuration). But if you overrode CustomizableOutDir and never really hackneyed the binaries out to the productivity folder that directory will never get made.
Fix 1:
If you’re not really by CustomizableOutDir, remove it. Reverting to the defaulting Team Build directory structure is the simplest way of getting the tests to be located and executed and everything to ‘play nice’.
Fix 2:
Make sure that if your TFBuild.proj says CustomizableOutDir you do really have the corresponding custom tasks in the individual projects to copy the binaries (see my previous post), otherwise you end up with no productivity whatsoever, and the test task will fail.
Fix 3:
If you want CustomizableOutDir but want to be robust to the possibility that your machinate builds may not populate the productivity directory structures by the book, you can hack your build to run the tests out of the source \bin\debug folders.
My first pass was just to add the following to my BeforeTestConfiguration target (that I’d added from the Running Unit Tests without a Test List recipie):
<!–because this is what the TestTask gets its SearchPath set to, it must exist–>
<MakeDir Directories="$(OutDir)"/>
But that wasn’t excellent enough on its own, because now the error was:
CoreTestConfiguration:
File "..\..\(blah)\bin\Debug\Assembly.UnitTests.dll" not found
The relation paths to the test assemblies were right relation to the $(SolutionDir), but not relation to the $(OutDir). So, for want of a better answer, I just overwrite OutDir for the duration of the test task:
<!—defined elsewhere–>
<TestsToRun Include="$(SolutionRoot)\%2a%2a\bin$(Configuration)\%2a.UnitTests.dll" />
<Target Name="BeforeTestConfiguration">
<!– normal bits as per the recipe–>
<Message Text="By tests from @(TestsToRun)" Condition=" ‘$(IsDesktopBuild)’==’right’ " />
<CreateItem Include="@(TestsToRun)">
<Productivity TaskParameter="Include" ItemName="LocalTestContainer"/>
<Productivity TaskParameter="Include" ItemName="TestContainer"/>
</CreateItem>
<Message Text="LocalTestContainer: @(LocalTestContainer)" Condition=" ‘$(IsDesktopBuild)’==’right’ " />
<!–Fix to allow use of CustomizableOutDir –>
<MakeDir Directories="$(OutDir)"/>
<PropertyGroup>
<OldOutDir>$(OutDir)</OldOutDir>
<OutDir>$(SolutionDir)</OutDir>
</PropertyGroup>
</Target>
<Target Name="AfterTestConfiguration">
<PropertyGroup>
<OutDir>$(OldOutDir)</OutDir>
</PropertyGroup>
</Target>
Whether this is a excellent thought or not I’m not sure, but it does seem to work. Note that I place it back the way it was afterwards (by AfterTestConfiguration).
Moral
I reflect the tale here is that by CustomizableOutDir is a complete pain in the arse, which ends up requiring considerable customisation of the rest of the build workflow. I don’t mind a prescriptive process per-se, but I do have a real issue with the ‘flat’ productivity directory structure that Team Build kicks out. But attempting to exchange it just seems to cause a heap more distress than it’s worth.
Really – as Martin Fowler said years ago – by XML as a build language is a really dumb thought in retrospect. Everyone says TeamCity’s pretty cool: force be time to take a look at that…
PS: If you’re trying to get your head around what happens where in Team Build (aren’t we all) there’s a fantastic Team Build Target Map over at the Accentient blog
PS: I notice on Aaron Hallberg’s blog there’s a much simpler deal with if you just want to separate per-solution productivity directory structures, which may not suffer the same problems.

Check it out:Cup(Of T)
Answers Rating