I needed to put 2 test assemblies into my automated CruiseControl.NET build and get coverage results. It appears that this is a pretty common need, with some tricks to get things working properly. According to http://www.kiwidude.com/blog/2006/10/ncoverexplorer-merging-ncover-reports.html, you need to either use an NUnit project file to contain all of the unit tests or merge the coverage xml files in the NCoverExplorer task. NUnit project setup and problems By using an NUnit project file, all of the tests are executed within one call, which produces one coverage.xml file. This allows tests from multiple test assemblies to be merged together into one coverage file that NCoverExplorer will understand automatically. <TestAssemblies Include="MyApp.Tests.nunit" />
MyApp.Tests.nunit contents: <NUnitProject>
<Config name="Default" binpathtype="Auto">
<assembly path="MyApp.DAL.Test\bin\Debug\MyApp.DAL.Test.dll" />
<assembly path="MyApp.Service.Test\bin\Debug\MyApp.Service.Test.dll" />
</Config>
</NUnitProject>
The major downside of this approach is that, according to http://nunit.com/blogs/?p=9, when using the NUnit project file, the config file that gets loaded needs to be based off of the NUnit project filename (i.e. in this case, MyAppT.Tests.config) and not the individual test assembly filenames. This means that we need to continually merge all of the app.config files into one "master" config file. This is not exactly a long-term, maintainable solution.
NCoverExplorer task setup
That brings us to the second possible solution presented above, namely to merge multiple coverage files together. To do this, you need to take some care in how you set the properties up for the tasks so that you don't overwrite coverage output files. My current build project looks similar to the one below. One other thing to keep in mind is to include the *.CoverageMerge.xml file in your CC.NET config file's <merge> section for this project. <ItemGroup>
<TestAssemblies Include="$(DALTestAssembly)" />
<TestAssemblies Include="$(ServiceTestAssembly)" />
<NCoverAssemblies Include="$(DALAssembly)" />
<NCoverAssemblies Include="$(ServiceAssembly)" />
<NCoverCoverageFiles Include="**.Coverage.xml" />
</ItemGroup>
<Target Name="Test" DependsOnTargets="CoreBuild">
<NCover ToolPath="lib\NCover\"
CommandLineArgs="%(TestAssemblies.FullPath) /xml=%(TestAssemblies.Filename).xml /labels /nologo"
CommandLineExe="lib\NUnit\nunit-console.exe"
CoverageFile="%(TestAssemblies.Filename).Coverage.xml"
LogFile="%(TestAssemblies.Filename).Coverage.log"
LogLevel="Verbose"
WorkingDirectory="$(MSBuildProjectDirectory)"
Assemblies="@(NCoverAssemblies)"
/>
<NCoverExplorer
ProjectName="MyApp"
ReportType="ModuleClassSummary"
OutputDir="$(MSBuildProjectDirectory)"
XmlReportName="MyApp.CoverageSummary.xml"
HtmlReportName="MyApp.CoverageSummary.html"
ShowExcluded="True"
SatisfactoryCoverage="80"
CoverageFiles="@(NCoverCoverageFiles)"
MergeFileName="MyApp.CoverageMerge.xml"
ToolPath="lib\NCover\Explorer"
/>
</Target>
To be sure, this is an incomplete list, but it is a good start. Here's what I don't like about LINQ to SQL: - It only works with MSSQL. Yes, this point has been beaten to death, but it is entirely justified. Third party solutions don't cut it. LINQ to SQL intentionally seeks to exclude a sizeable population because of this hair-brained decision.
- No way to easily specify adhoc LINQ queries. This doesn't count. I know the benefits of design-time queries, but I should also be allowed to shoot myself to get the added flexibility if I so choose. Building up expression trees is not a viable option for every day development.
- The constant labeling of LINQ to SQL as an OR/M. That label considerably overstates what this technology does. One to one mapping between a table and a class is not really OR/M. It seems like they want to force you to change your database by writing stored procs and views to make your object model better.
- There is no automated way to easily pick up changes to the database schema.
- There is no easy way to preserve changes to the generated code. e.g. I change the name of the automatically generated class from collection_details to CollectionDetails, but I evolve the schema of the table. When I re-add the table, I need to set all of the custom properties again. I know I shouldn't change generated code, but see the next point.
- Speaking of collection_details, it would be much better if the underlying class generator had some options to clean up legacy table names (e.g. remove underscores, camel case resulting table and column names).
- No many-to-many support. In short, when you have an junction table (aka associative table or cross-reference table), you will need to write code like this: User.UserPermissions[0].Permission vs. User.Permissions[0]. Until we see LINQ to Entity (if ever), we do have this, but you can't use the new entity in a LINQ query.
- There is no built-in solution to using LINQ across tiers. I don't want to expose my LINQ classes (see the point above about the tight coupling between database and objects) as I may want to change my database, and I don't want that cascading to all of the places that use it. There is also no diffgram, so even if I did it, I would have to write my own change tracking and resolving support. I went to an OpenSpaces meeting on this very topic during CodeMash, and the consensus was not flattering.
In short, it seems like this part of LINQ was released way before it was ready. But it does demo well... Feel free to add your own grievance to the comments.
I have a PATH that is miles long, and I needed to find out where a certain application was launching from. On a good operating system, this kind of functionality is built in. On a Windows operating system, you can create a BAT file, or download a utility.
I have been reading Dustin Campbell's series, The 12 Days of Refactor! X-mas, with interest. He's a very good writer, and has broken down a bunch of Developer Express features into easy to digest chunks of information. The episode I linked to above touched on the XML Literal support that shipped with VB in Visual Studio 2008. The one sentence summary of this technology is that it lets the VB compiler translate raw XML in the source code into strongly-typed code using XML classes under the hood. It's a very nice idea, and I encourage you to look at the links to learn a little more about it. While the VB team thought this was a good idea and added the feature, Anders and the C# team believed that it was superfluous to add such a thing to the C# side. I haven't really made up my mind which group I side with yet. However, Anders is benevolent , so he gave us the little-documented PasteXmlAsLinq addin that will take XML on the clipboard and paste it into a file in C# syntax building the XML up using classes like XElement. In a default install of VS2008, open C:\Program Files\Microsoft Visual Studio 9.0\Samples\1033\CSharpSamples.zip and extract the LinqSamples\PasteXmlAsLinq files. There is a Readme.html file in there that tells you how to build, install and use the addin. While this isn't the same as VB's support for XML Literals, it does make things easier to work with.
Things I learned this week (sorry, Carl!): - The Cisco VPN Client software is very fickle. In order to upgrade from 4.8 to 5.0, you need to uninstall and install, with reboots to be found everywhere.
- Installing an entire slew of MS updates is usually a good idea to keep your system up to date.
- Even though your computer works fine at home, you can't rely on it working the same way when you get to work. For example, you might have internet access at home with no problems, but when you get to work, traffic over port 80 will suddenly stop about 5 minutes from the time you power up. https, ftp, email, IM, and everything else will continue to work just fine. Just no http traffic over port 80.
- 5 minutes is not a lot of time to conduct google searches to find out what's wrong.
- MS System Restore is implemented about as horribly as anything I've ever seen.
- After running System Restore, the problem does not go away.
- To make matters worse, System Restore totally hosed my Office install where it deleted a bunch of files from MSOCache, thereby causing my Office products to not be able to launch properly, or even uninstall.
- After copying missing files back to MSOCache, all of the Office applications claimed they needed to repair installs upon launch. Every time.
- MS has really good directions for how to manually uninstall Office 2007.
- Seconds before doing a complete wipe of your system, it's a good thing to double check with friends who have Google-Fu.
- It turns out that c:\windows\system32 has 2 files: vsdatant.dll and vsdatant.sys. These files get linked with ZoneAlarm a lot in google searches, but they are also used by the Cisco VPN Client. Something in the Cisco (un)installer caused rogue versions of these files to be left in my system. Rebooting to Safe Mode to clean these files up (along with the registry entries) finally got things back to normal.
And that, my friends, is what I learned this week. Now where's that next Monday's episode?!?
At the risk of another "Me, too!" post, I thought I'd highlight several links that I have found to be helpful, and for a value-added bonus, talk about why this release matters to me. Back in the day (oh boy, does that make me sound old!), I learned how to program for the Internet by using straight HTML and Delphi to create CGI and ISAPI extensions. In order to do this, you needed to be quite aware of how the actual protocols worked, and what to do to make things behave as you'd expect. I stayed with web development up until I was using COM objects (again, written in Delphi) from an ASP page. After that, I wasn't into the web development scene much on a full-time basis. ASP.NET 1.0 and 2.0 came along, and I found them to be quite daunting. It seemed as if it was framework built upon framework, layered with add-ins to do what I thought used to be simple things. It appears to me that there has been a resurgence to move away from the barrage of constant abstractions, and to instead embrace the simplicity of the web (see the popularity of REST, Rails, and the buzz around ASP.NET MVC for some examples of this). So for me, the reason I am excited is that not only can I once again utilize my knowledge about how the web works, but I can use it in new ways that will make my applications even better (e.g. TDD, scaffolding, etc.). At any rate, here's the set of links that I think matter for ASP.NET MVC:
I wanted to attend CodeMash last year, but waiting until the last minute worked against me. This year I made sure to commit to the event early, so I just signed up and got my hotel reservations sorted out. The sessions look to be pretty deep for a smaller conference, and I'm excited about going there to talk shop.
If you'll be going, drop me a line via comment here, and we'll be sure to sit down and have a beverage or 2. If you're in the Milwaukee/Madison area, and want to chat ALT.NET, it might be a good place to formally plan and launch the Milwaukee meetup.
Hope to see you there!

If you see an error like the following: MSB6006: "NCover.Console.exe" exited with code 1. in build.proj(93, 3)
be sure to check that you are using the correct version of CoverLib.dll. In older versions of NCover (e.g. 1.5.8), by default, this dll should be registered every time the NCover task is run. I haven't found that to be true, though. I had an older version of NCover installed somewhere else on the build machine, and I kept on having my build fail because version 1.5.8 of NCover.Console.exe was loading version 1.5.5 of CoverLib.dll.
By manually registering the correct version of CoverLib.dll, I got the build working again.
|