How does shim work?

As we all know, fakes come in two flavors: stub and shim. From the MSDN article Isolating Code Under Test with Microsoft Fakes, we are informed that

A shim modifies the compiled code of your application at run time so that instead of making a specified method call, it runs the shim code that your test provides.Shims can be used to replace calls to assemblies that you cannot modify, such .NET assemblies.

But how does shim modify the compiled code? By which mean?

Let's take a look at the Moles, ancestor of Fakes framework, which is created by Microsoft Research. There is an article Moles: Tool-Assisted Environment Isolation with Closures listing the details. you can find the article in this book Objects, Models, Components, Patterns

Answer can be found in section 4.1

The Moles framework builds on top of the Extended Reflection code instrumentation framework to realize the detouring of method calls. Extended Reflection is also used byPex and CHESS[11]. The details of the code instrumentation are hidden from the user who interacts only with the generated high-level mole types described in Section 4.2.The instrumentation is done as follows. At the beginning of each method some code is inserted. This code queries a low-level detours library as to whether any detour was attached to this particular method. If so, then the detour delegate is invoked, otherwise,the normal code is executed.

For example, consider the following method.

string Compute(int x, int y) {
   return (x+ y).ToString();
}

After instrumentation, the code will be similar to the following pseudo-code.

string Compute(int x, int y) {
   // obtain identifier of this method
   Method thisMethod = this.GetType().GetMethod("Compute",new Type[]{typeof(int), typeof(int)});
   // query if a detour has been attached
   Delegate detour = _Detours.GetDetour(this, thisMethod);
   if (detour != null) {
       // pseudo-code; actual implementation avoids boxing
       return (string)_Detours.InvokeDetour(detour, this, new object[] { x, y });
   }
   // else execute normal code
   return (x + y).ToString();
}

The Extended Reflection mentioned above is another framework sponsored by Microsoft Research, it contains a main part, called ClrMonitor, as they say

The ClrMonitor is an unmanaged COM component that implements the CLR profiling API. It uses this API mainly to rewrite MSIL instructions of selected methods, types or assemblies on-the-fly at JIT time. It can redirect calls and insert callbacks in the MSIL instruction sequence, enabling the observation of the execution of the program at a fine grained level

The solution of shim should be clear now, and the web page CLR Profiler is a good place to explore the CLRProfiler. Have fun!

你可能感兴趣的