Unit Testing with Roslyn
• CommentsRoslyn
Roslyn was a huge project that spanned many years. It was a difficult rewrite of the C# and VB compilers into managed code, with the intent of also enabling fast analysis of partial code segments. These days, Roslyn powers many different systems: the compiler itself, the little hints that pop up as you type, and even static analysis systems that you can bundle with your NuGet package to encourage proper usage.
I’ve thought many times about using Roslyn to create some analyzers for common mistakes with Task
and async
, but I’ve just never taken the time to do it. However, just recently, I had the opportunity to use Roslyn for something completely different.
DotNetApis
I run a service called DotNetApis that autogenerates reference documentation for NuGet packages. It does this by walking the CLI metadata (using the awesome Mono.Cecil) and matching accessible elements with their XML documentation.
The code that currently runs that site is a bit of a mess. I’ve been cleaning up the code into a v2 that is open-source through and through. As a part of this rewrite, I needed a way to unit test some odd code elements. In the v1 code, I had a single “test”/”sample” dll that had a bunch of weird members, and I ran my unit tests against that. This worked, but I wanted my unit tests to be more self-contained.
Enter Roslyn.
I have unit tests in DotNetApis v2 that need to compile some code (as a string
) and then parse the resulting dll and xml. Getting this working was surprisingly easy!
This beautiful little utilty method takes C# code and spits out a parsed dll and xml file, all in-memory! The actual code is a bit more complex for efficiency reasons. I currently have 86 unit tests using this method, with lots more on the way!
Here’s what one of the unit tests looks like:
This unit test is checking that the Xmldoc Identifier calculated by DotNetApis is in fact what we expect it to be (M:SampleClass.SampleMethod
) and that it matches what the C# compiler generated in the xml file. The AssertXmldoc
helper is taking the Xmldoc Id from DotNetApis, looking it up in the *.xml file from the compiler, and asserting that the text we extract is what is expected.
Sure, this example is pretty easy, but I’ve also started adding the more rare cases like methods that take an array of pointers by reference. There’s a lot of more complex cases that are undocumented, and we have to rely on observed compiler behavior.
Roslyn is Cool
That’s all I have to say. I just thought it’s so cool how easy Roslyn made this. And it’s fast, too! I can keep my Live Unit Testing running while hacking around, even with most of my tests running Roslyn, and it’s all pretty slick!