Friday, April 4, 2008

Unit Tests and the InternalsVisibleTo Property

Confusion

The other day I ended up making the decision to strong name a series of assemblies. It also usually means revisiting some config files somewhere and re-referencing the same dll's all over again but with a strong name. Of course there's many benefits to strong naming but that's not what this is about.

What I DIDN'T see coming was how this would throw a wrench into my unit tests. Normally when you create Unit Tests under Visual Studio if you are testing internal (friend in VB) methods it will automagically add the System.Runtime.CompilerServices.InternalsVisibleTo attribute on the assembly that is going to be unit tested. But the moment I strong named the assembly I wanted to run tests on I ended up getting the following error:

Friend assembly reference 'Foo.Bar.Test' is invalid. Strong-name signed assemblies must specify a public key in their InternalsVisibleTo declarations.

I dug through some MSDN documentation and found that it wanted me to do just that, instead of:

[assembly: InternalsVisibleTo("Foo.Bar.Test")]
I was supposed to use a syntax that specified the PublicKey, like so:
[assembly:InternalsVisibleTo("Foo.Bar.Test, PublicKey=32ab4ba45...")]

It took a bit of thinking for this to finally make sense to me. Strongly Named assemblies don't mind exposing their internals to other assemblies, but they'd at least like them to also be strongly named AND have have us specify the public of any assembly that's going to be digging around in its internals.

This means we have to strong name the Unit Test assembly as well.

In addition we still need to get the Public Key off of the Unit Test assembly after we strong name it.

It's important to note that the PublicKey is NOT the PublicKeyToken that you might acquire through Reflector and is part of the strong name. The PublicKey is the value of the public key extracted from the Key Pair/.snk file with the sn.exe utility.

Solution

You can extract the public key from an .snk with the sn.exe tool from the .NET SDK. First we extract just the public key from the key pair (.snk) file into another .snk file.

sn -p Foo.Bar.Test.snk Foo.Bar.Test.PublicKeyOnly.snk
Then we ask for the value of that public key:
sn -tp Foo.Bar.Test.PublicKeyOnly.snk

We end up getting a super LONG string of hex, but that's just what we want, the public key value of this key pair.

We add it to the strongly named project that we want to expose our internals from and we're good to go. Before what looked like:

[assembly: InternalsVisibleTo("Foo.Bar.Test")]
Now looks like.
[assembly: InternalsVisibleTo("Foo.Bar.Test, PublicKey=00240000048000009 40000000602000000240000525341310004000001000100354f0966de4a992baa1ed0f2 faf643f86fd2c74aee8b9dc6c0321f9d658166658ec154aaed70ab4b92a21a3c1e7e53 200232043c0d0b791496fd0201d21f18433ee9507022f2a72829d1dd32b106f86c68e 620d2a39f02f3a8b82aa23196ef7f7f4880020dd340dd2dfecdd1b3051b1e659c9e18c 8e21cc90bc33de306712b86")]

And we're done.

Hope that helps,
Tyler

4 comments:

Anonymous said...

Wow, thank you so much. You save me from evil thinking converting internal to public for testing :D

Jocker said...

Thanks,
Its really a helpfull information.
But even after following all step properly i was getting another error as "Friend access was granted to test project".

i signed my test project with the same key. it started working fine. Didnt see this info in your blog. so thouhgt of adding it..

Tyler Holmes said...

Thanks Jocker, appreciate the feedback.

Best,
Tyler

Anonymous said...

Thanks! This article was very helpful and saved me many hours of digging and experimentation.