vanderkleij/Smocks

Smocks doesnt support method that takes local reference variables as a parameters.

Karthik-Venkatesalu opened this issue · 3 comments

Mocking a method requires parameter values to be matched.
This works fine for values types and member reference variables.

I came across a situation where my mocked method takes local reference variable as the parameter. And mocking this method does not return the mocked return value.
Something similar to below.

[TestClass]
public class UnitTest2
{
    [TestMethod]
    public void TestMethod1()
    {
        Smocks.Smock.Run(context =>
            {
                object obj = new object();
                context.Setup(() => SomeStaticClass.GetId(obj)).Returns(10);

                SomeClass sc = new SomeClass();
                var id = sc.GetId();    // which doesnt return mocked value '10'
            });
    }
}

public class SomeClass
{
    public int GetId()
    {
        object obj = new object();
        return SomeStaticClass.GetId(obj);
    }
}

public class SomeStaticClass
{
    public static int GetId(object obj)
    {
        return 55;
    }
}

Can you suggest a solution for this?

This is by design. For reference types, a setup is only matched if the provided argument is the same (ReferenceEquals).

Consider the following compact version of your example:

public static void TestMethod1()
{
   Smocks.Smock.Run(context =>
   {
      object object1 = new object();
      object object2 = new object();

      context.Setup(() => SomeStaticClass.GetId(object1)).Returns(10);

      Console.WriteLine(SomeStaticClass.GetId(object1)); // Outputs 10
      Console.WriteLine(SomeStaticClass.GetId(object2)); // Outputs 55 (default implementation)
   });
}

The setup matches object1 but not object2, as object1 was used in the setup.

This behaviour is identical to Moq's behaviour. This is the same example converted to Moq:

public static void TestMethod2()
{
   object object1 = new object();
   object object2 = new object();

   var mock = new Mock<IFoo>();
   mock.Setup(foo => foo.GetId(object1)).Returns(10);

   Console.WriteLine(mock.Object.GetId(object1)); // Outputs 10
   Console.WriteLine(mock.Object.GetId(object2)); // Outputs 0 (default)
}

Right now, you could try to use It.IsAny<object>() so that any object matches the setup. Support for Moq-alike It.Is(obj => ...), so that you can specify the conditions used for matching a setup yourself, is on Smock's roadmap.

It solves this issue. Thanks a lot for your quick response.

I have one more issue.
While continuing the testing, method under the test throws "InvalidProgramException - Common Language Runtime detects invaild program" exception.

Calling the same method outside the smock context, works fine.
From my search, I found that this exception occurs when there is mismatch in generated IL.

Just to know, is this problem relates to Smock?

Method which I am testing is an extensive method which has around 2k lines of
code.
Your advice is greatly aprreciated on this.

That is most likely a Smocks issue indeed. In order to fix it, I'll need a minimal code example (preferably < 2k lines) that reproduces the issue. If you can provide such an example, please open a separate issue for that problem with the code sample. I'll close this issue for now.