chevron-thin-right chevron-thin-left brand cancel-circle search youtube-icon google-plus-icon linkedin-icon facebook-icon twitter-icon toolbox download check linkedin phone twitter-old google-plus facebook profile-male chat calendar profile-male
0 votes
I made simple windows form with 2 button on it, button 1 is to prepare and test, button 2 is to act.

problem 1.
when I click on button 1 and then button 2, it will fake the method, but the passed parameter is not correct. it's the value I used when I was in preparing phase, not the actual value passed to the method, when I do it without using reference parameter passing, everything will be fine. but in my real scenario I have to use reference parameter passing.

problem 2.
when I click button 2 first and then button 1, it will throw an exception that contains:

*** No method calls found in recording block. Please check:
* Are you trying to fake a field instead of a property?
* Are you are trying to fake mscorlib type?

It means that if original method is called once before faking, we can not fake it anymore.

I can handle problem 2 by prevention of calling original method before faking, but I don't know what to do with problem 1.


here is my code:
namespace TypeMocTestAPP
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        
        [TestMethod]
        private void button1_Click(object sender, EventArgs e)
        {
            //Prepare
            var fake = Isolate.Fake.Instance<TestClass>();
            DateEx dateEx = new DateEx { Day = 1, Month = 2, Year = 2000 };
            Isolate.WhenCalled(() => fake.DateToString(ref dateEx)).DoInstead(context =>
            {
                string param0 = ((DateEx)context.Parameters[0]).Year.ToString();
                return "Fake is Called, Year is:" + " " + param0;
            }
            );
            Isolate.Swap.AllInstances<TestClass>().With(fake);
        }

        private void button2_Click(object sender, EventArgs e)
        {
            //ACT
            TestClass testClass = new TestClass();
            DateEx refDate = new DateEx() { Year = 1999, Month = 11, Day = 1 };
            MessageBox.Show(testClass.DateToString(ref refDate));
        }

    }

    public struct DateEx
    {
        public int Year;
        public int Month;
        public int Day;
    }

    public class TestClass
    {
        public string DateToString(ref DateEx dateEx)
        {
            return "Original is Called, Year is: " + " " + dateEx.Year.ToString();
        }
    }
}
asked by mike1010 (680 points)

5 Answers

0 votes
Hi Mike,

The Isolator is built to work with test runners like mstest, nunit etc.
The behavior of the Isolator when running it inside winform application can be odd to say the list :)

Usually you create a separate test project and add a reference to the code you want to test.

As for the problems:
1. The behavior of the ref parameter is by design.
When you send a ref or out parameter to a faked method the Isolator treats it as if you want to fake the parameter value.
See the documentation for ref and out behavior here

2. Do you get the same behavior when you run a 'standard' test method? (using mstest and inside a test project.)
answered by ohad (35.4k points)
0 votes
Hi Ohad,

Thanks for your answer, I was just testing the functionality. I will test it in real test project.

About ref parameters, I've read the documentation. Is there any way to fake a method with ref parameters without faking parameter values with Isolator ?
because I don't want to change original method itself, and I don't want to provide my faked parameter values, I need the real passed values inside my faked method.

Best Regards,
Mike
answered by mike1010 (680 points)
0 votes
Hi Mike,

This feature is not supported.
Can I ask what is the use case for the feature?
When you fake a method the body of the method will not run, so you can just send the value you want as ref argument.
answered by ohad (35.4k points)
0 votes
Hi Ohad,

I had a method with ref parameters in another assembly that I can not modify it's body by changing the source code, and it acts strange sometimes. It's getting called many times during a test indirectly, I want to replace it's body with my own method body so I can log all inputs and also return correct calculated values based on given parameters and correct expected logic implemented by myself in fake method body, so I can test the rest of the project. finally if the problem is form this method, I have to rewrite the whole class library which contains this method, because I do not have access to the source code anymore.
answered by mike1010 (680 points)
0 votes
Hi Mike,

The solution as I see it is using the old API - reflective mocks.
In this API you have to specify that you want to fake ref parameters so by default you'll see the original parameters values.

Also please note that in reflective mocks you are using strings to specify the methods names and there is no such thing as Recursive fakes :(

Example:
[Test]
public void Test()
{
    // this is the same as Isolate.Fake.Instance and Swap.AllInstances
    // in one line :)
    Mock mock = MockManager.MockAll<TestClass>();
    //This is the same as DoInstead()
    mock.AlwaysReturn("DateToString", new DynamicReturnValue((prm, context) =>
    {
        DateEx d = (DateEx)prm[0];
        if (d.Year == 3)
        {
            return "three";
        }
        return "one";
    }));

    DateEx dt = new DateEx() { Day = 1, Month = 2, Year = 3 };
    TestClass tc = new TestClass();
    string res = tc.DateToString(ref dt);

    Assert.AreEqual("three", res);
}


Hope it helps.
answered by ohad (35.4k points)
...