Using CThru to Fake Entire Assemblies

In our forums, Soon Hui Ngu asked if there’s a way to fake recursively entire assemblies, without too much hustle. And the answer is – almost! In the current implementation of CThru, you can’t do it recursively. But you can use CThru to do almost that. You can fake all types almost without any work. Here’s how:

First define an Aspect (which conveniently derives from CThru.Aspect). In my case, I’m interested in changing behavior of methods of different assemblies. So here’s my class:

    public class DependentAssemblyAspect: Aspect
{
public static List<Assembly> AssembliesToFake = new List<Assembly>();

public event Action<DuringCallbackEventArgs> OnMethodBehaviorCallback =
e =>
{
foreach (Assembly assembly in AssembliesToFake)
{
if (assembly.GetType(e.TypeName) != null)
{
e.MethodBehavior = MethodBehaviors.SkipActualMethod;
}
}
};

public override void MethodBehavior(DuringCallbackEventArgs e)
{
OnMethodBehaviorCallback(e);
}
}

Let’s see what we’ve got here. First a field containing the assembly list. I’m going to add Assembly objects from my test to this list. Second, I have an event handler that looks at what method that gets invoked, and selects its behavior based on belonging to the assemblies in our list. In our case, we select SkipActualMethod, in order to fake the methods.

The test looks like this:

[TestMethod]
public void FakeBehaviorsOnTypesFromDependentAssemblies()
{
// Add dependent assemblies to list - current and external
DependentAssemblyAspect.AssembliesToFake.Add(Assembly.GetExecutingAssembly());
DependentAssemblyAspect.AssembliesToFake.Add(Assembly.LoadFrom(@"C:MyLibrariesTestClassLibrary.dll"));

// Add the aspect to CThru
var aspect = new DependentAssemblyAspect();
CThruEngine.AddAspect(aspect);
CThruEngine.StartListening();

// Execute from external assembly
TestedClass tc = new TestedClass();
tc.exception();

// Execute from this assembly
MyClass.Do();
}

Ok, that works on calls from both assemblies. What if I have this test:

[TestMethod]
public void FakeRecursiveBehaviorsOnTypesFromDependentAssemblies()
{
// Add dependent assemblies to list
DependentAssemblyAspect.AssembliesToFake.Add(Assembly.GetExecutingAssembly());

// Add the aspect to CThru
var aspect = new DependentAssemblyAspect();
CThruEngine.AddAspect(aspect);
CThruEngine.StartListening();

// Execute from this assmbly
MyClass mc = new MyClass();
mc.GetAnotherClass().DoSomething();

}

This time I have a recursive behavior. If you run it, you’ll see that GetAnotherClass returns null (which is the current behavior). How can I override that? Let’s update the Aspect to return a recursive fake for that method:

public event Action<DuringCallbackEventArgs> OnMethodBehaviorCallback =
e =>
{
if (e.MethodName.Contains("GetAnotherClass"))
{
e.MethodBehavior = MethodBehaviors.ReturnsCustomValue;
e.ReturnValueOrException = Isolate.Fake.Instance<AnotherClass>();
return;
}

foreach (Assembly assembly in AssembliesToFake)
{
if (assembly.GetType(e.TypeName) != null)
{
e.MethodBehavior = MethodBehaviors.SkipActualMethod;
}
}

};

I’ve added the if statement for the specific method. For that method specifically, I return a fake object. I also set the MethodBehavior property correctly.

So we can, based on method and type,  do without lots of specific coding per test. Give it a try, and play with it a little. As I’ve discovered making this example, there are a few things missing here. I’d like to get your input on what can be added.

  • Soon Hui

    Thanks! Wow, interesting approach :)

  • Gil Zilberfeld

    It’s only the beginning! There’s a lot you can do with CThru.

TOP