简体   繁体   中英

How do I ignore the assembly reference mismatch in unit tests?

I'm experimenting with tampering of the assemblies in order to be able to mock the code which cannot easily be mocked, such as SharePoint assemblies .

As a prototype, I have a solution where the tested code is tampered through a custom build action with ILRepack and Mono.Cecil, so that the actual code is not the one which was originally written.

When the assembly containing the tested code is not signed, everything works well. When the assembly is signed, I see the well expected error:

The located assembly's manifest definition does not match the assembly reference.

Since the assembly is tampered, obviously, the key is either not the same (if signed after tampering) or doesn't exist.

I thought that passing by AppDomain.CurrentDomain.AssemblyResolve event could allow forcing the tampered assembly to be accepted, but it's not.

How do I ask .NET Framework to ignore the checking of assembly matching during unit tests running in full trust, and accept unsigned assemblies when it expects them to be signed?


As I understand it, the problem is not strong name validation. Not only the error would be different, but also running the corresponding sn –Vr has no effect: the error is still there.

The actual problem seems to be at the assembly binding level. This is also why I'm surprised to see that AppDomain.CurrentDomain.AssemblyResolve event is raised, but its result is still ignored; probably, it doesn't do what I always thought it did.

The solution is much easier that I thought. Since, as I guessed, the problem is not strong name validation, but assembly binding relying on the public key token, one can replace the token while tampering the assembly.

The first step is, before tampering, to get the original public key and public key token. They are both inside the AssemblyName .

var originalAssemblyBytes = File.ReadAllBytes(originalFilePath);
var originalAssemblyName = Assembly.Load(originalAssemblyBytes).GetName();

The next step is the tampering itself: first the merge of two assemblies using ILRepack, then more granular changes with Mono.Cecil. During this second step, Mono.Cecil is used to replace the public key and the public key token:

var assemblyName = mergedModule.Assembly.Name;
assemblyName.HasPublicKey = true;
assemblyName.PublicKey = originalAssemblyName.GetPublicKey();
assemblyName.PublicKeyToken = originalAssemblyName.GetPublicKeyToken();

It is essential to change both: if only the token is changed, the error “Invalid assembly public key” is thrown as soon as the assembly is used.

This works for both assemblies signed with .snk and with .pfx: since tests are running in full trust, the validation is not done, meaning that the fact that the public key doesn't correspond to the private key is irrelevant.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM