How to use Microsoft Shims to detect method call being DAMP
c#, lambda, unit-testing
Solution
Instead of passing a boolean parameter, pass in a very simple class that wraps the boolean parameter.
public class MethodTracer{
public bool WasCalled{ get; set; }
}
That will always be passed by ref, doesn't suffer from funny lambda tricks and might even be considered more readable than a simple boolean variable.
Adding aggressive inlining, `ref` parameters or `out` parameters doesn't make your method more DAMP. It will just confuse the hell out of people :).
[TestMethod]
public void ATestMethod()
{
//Arrange the test...
MethodTracer tracer = new methodTracer();
using (ShimsContext.Create())
{
ShimMyClass.AllInstances.MyMethod = _ => { tracer.WasCalled = true; };
//Act...
}
Assert.IsTrue(tracer.WasCalled);
}
Or have your method actually return the tracer:
private MethodTracer DetectIfMyMethodHasBeenCalled()
{
MethodTracer tracer = new MethodTracer();
ShimMyClass.AllInstances.MyMethod = _ => { tracer.WasCalled = true; };
return tracer;
}
Making your test:
[TestMethod]
public void ATestMethod()
{
using (ShimsContext.Create())
{
var myMethodCallTracer = DetectIfMyMethodHasBeenCalled();
Assert.IsTrue(myMethodCallTracer.WasCalled);
}
}
Problem
I bump into the following problem writing some unit tests. I want to test if a method of a class was called in the SUT. I used Microsoft Shims as the method belongs to an class which doesn't implement any interface (Stubs cannot be used). The shim intercept the method call and set a variable to true into a lambda. The variable is defined outside the lambda but in the same scope so the variable is captured. The problem rises when I try to refactor the code to be DAMP (Descriptive And Meaningful Phrases) using a function, with a descriptive name, to wrap up the shim creation, and so the lambda. I am forced to pass the variable to the function and then having the lambda capturing it, but this cause the changes to the variable to be confined in the scope of the function. I cannot use ref on the parameter as I am getting an error. I tried to force the function inline using aggressive inline custom attribute but without any success. As C# doesn't support macro, how I can be DAMP confining the shim into a function rather than have it in the unit test code making it quite unreadable? This is the code with the shim setup into the test method: ``` [TestMethod] public void ATestMethod() { //Arrange the test... bool myMethodHasBeenCalled = false; using (ShimsContext.Create()) { ShimMyClass.AllInstances.MyMethod = (x) => { myMethodHasBeenCalled = true; }; //Act... } Assert.IsTrue(myMethodHasBeenCalled); } ``` This is instead how i would like to have my code... ``` private void DetectIfMyMethodHasBeenCalled(bool flag) { ShimMyClass.AllInstances.MyMethod = (x) => { flag = true; }; } [TestMethod] public void ATestMethod() { //Arrange the test... bool myMethodHasBeenCalled = false; using (ShimsContext.Create()) { DetectIfMyMethodHasBeenCalled(myMethodHasBeenCalled); //Act... } Assert.IsTrue(myMethodHasBeenCalled); } ```