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
Welcome to Typemock Community! Here you can ask and receive answers from other community members. If you liked or disliked an answer or thread: react with an up- or downvote.
0 votes
I think I might be hosed on this one - I have to deal with this legacy library controlled by another team.

The signature of what I'm calling is this:

void LegacyGetAll(ref Results[] results)


As we all know this should be:
Results[] GetAll()


But I have no control of this.

How the heck to do fake this??? I want to stick with AAA if possible because it's the 'easiest' to set up tests for.[/i]
asked by boo (21.8k points)

6 Answers

0 votes
Hi

Unfortunately faking is not supported in the AAA API :(
But it's pretty easy doing it in natural mocks.
You just have to create the faked ref argument outside the recording block.
Here is an example:
public void Test()
{
    Results [] fakeResults = new Results[5];
    for (int i = 0; i < 5; i++)
    {
        fakeResults[i] = new Results();
        fakeResults[i].x = 10;
    }
    
    using (var expectations = RecorderManager.StartRecording())
    {
        SomeClass fake = new SomeClass();
        fake.LegacyGetAll(ref fakeResults);
    }

    Results [] results = new Results[5];
    SomeClass someClass = new SomeClass();
    someClass.LegacyGetAll(ref results);

    Assert.AreEqual(results[0].x, 10);
}
answered by ohad (35.5k points)
0 votes
Ohad
This is fully supported in the AAA, using the same technique - the ref value that you pass into the WhenCalled statement will be the fake returned value in the real statement so you can do the following:
(I assume that Results has 1 property: Number and the actual test is bogus and just proves the point)

[Isolated, TestMethod]
public void Test()
{
    var classUnderTest = new ByRef();
    var fakeResults = new Results[] { 
          new Results { Number = 1 }, new Results { Number = 2 } };

    // Here is where we Isolate and return the fakeResults
    Isolate.WhenCalled(()=>classUnderTest.LegacyGetAll(ref fakeResults)).IgnoreCall();


    //Lets just see that this works.
    var actualResults = new Results[] { 
          new Results { Number = 10 }, new Results { Number = 10 } };
    classUnderTest.LegacyGetAll(ref actualResults);

    Assert.AreEqual(1, actualResults[0].Number);
    Assert.AreEqual(2, actualResults[1].Number);
}


:arrow: Note: there is a problem/bug when the number of items in the fake array is not the same as the actual array
answered by eli (5.7k points)
0 votes
So since I'm having to fake, would it be:

[Isolated(), TestMethod()]
public void Test()
{
      //Arrange
      var fakeResults = new Results[] { new Results { Number = 1 }, new Results { Number = 2 } };
      Isolate fakeClass = Isolate.Fake.Instance<SomeClass>();
      Isolate.WhenCalled(() => fakeClass.LegacyGetAll(ref fakeResults)).IgnoreCall();

      //Act
      SomeOtherClass target = SomeOtherClass.MethodThatUsesLegacyGetAllInternally();

     //Assert
     Assert.IsNotNull(target);
     Isolate.WasCalled.WithAnyArguments(() => fakeClass.LegacyGetAll(ref fakeResults));


That's *almost* my *real* test.

I worked around the issue by creating a 'helper' test class (10 lines) and using CallsOn, and then later found I didn't actually need the method/test at all - but for next time - it will be good to know that the above would work.
answered by boo (21.8k points)
0 votes
Hi Brian

Don't forget to swap next instance of SomeClass with your fake instance
since its created internally in MethodThatUsesLegacyGetAllInternally

var fakeResults = new Results[] { new Results { Number = 1 }, new Results { Number = 2 } };
var fakeClass = Isolate.Fake.Instance<SomeClass>();
Isolate.WhenCalled(() => fakeClass.LegacyGetAll(ref fakeResults)).IgnoreCall();
Isolate.Swap.NextInstance<SomeClass>().With(fakeClass); // <== don't forget
answered by ohad (35.5k points)
0 votes
Does AAA syntax also work for static class/methods? I could not get the ref parameter to be updated and had to resort to ohad's Natural Mocks version.

I have a P/Invoke wrapper method GetStatus in StaticClass with a reference to a StatusStructure structure and returns a boolean.

// Arrange  
StatusStructure fakeStatus = new StatusStructure { StatusValue = 1 };

Isolate.Fake.StaticMethods(typeof(StaticClass));
Isolate.WhenCalled(() => StaticClass.GetStatus(ref fakeStatus)).WillReturn(true);

// Act
StatusStructure status = new StatusStructure();
bool result = StaticClass.GetStatus(ref status);
answered by jberd126 (760 points)
0 votes
Hi

There is bug regarding ref / out parameters in AAA.
The bug is that it that the value of ref parameters is not set when the default behavior is Members.ReturnRecursiveFakes.
This is the default behavior when using AAA syntax.
The workaround is to use different default behavior like Members.ReturnNulls:
// Arrange 
StatusStructure fakeStatus = new StatusStructure { StatusValue = 1 };

Isolate.Fake.StaticMethods(typeof(StaticClass), Members.ReturnNulls);
Isolate.WhenCalled(() => StaticClass.GetStatus(ref fakeStatus)).WillReturn(true);

// Act
StatusStructure status = new StatusStructure();
bool result = StaticClass.GetStatus(ref status);    

// Assert
Assert.AreEqual(1, status.StatusValue);
Assert.AreEqual(true, result);


This should make the test work.
I hope we'll fix this problem soon :oops:
answered by ohad (35.5k points)
...