5

Is there a possibility to isolate / replace an constructor of a class with Microsoft Fakes?

In found an example for Mole (antecessor of Fakes): http://thecurlybrace.blogspot.co.at/2011/11/how-do-i-detour-mole-type-constructor.html

I tried constructs like this

ShimStreamReader.Constructor = @this => ShimStreamReader.ConstructorString(@this, "Test");

but it says the get accessor is missing. To clarify it would be nice to replace something like

new StreamReader("filename")

with static input like this

new StreamReader(new MemoryStream(Encoding.Default.GetBytes("33\r\n1\r\n16\r\n5\r\n7")))

so that i do not have to mock Read, ReadLine, etc.

mimo
  • 6,221
  • 7
  • 42
  • 50
Dresel
  • 2,375
  • 1
  • 28
  • 44

2 Answers2

6
using (ShimsContext.Create())
{
    ShimStreamReader.ConstructorString = 
        delegate(StreamReader @this, string @string)
        {
            var shim = new ShimStreamReader(@this);
            shim.Read = () => 42;
        };

    var target = new StreamReader("MeaningOfLife.txt");
    Assert.AreEqual(42, target.Read());
}
Oleg Sych
  • 6,548
  • 36
  • 34
  • What you want is an emulated StreamReader. That's not something we can generate. You'd have to build it. – Oleg Sych Oct 25 '12 at 21:19
  • I don't know what you mean with emulated StreamReader, but it was possible detouring (or replacing) a constructor call in Moles (see sample above), and i thought it may be possible in Fakes. I tried different solutions (like putting the "new StreamReader("filename")" call into a method and replacing the whole method with "new StreamReader(new MemoryStream(Encoding.Default.GetBytes("33\r\n1\r\n16\r\n5\r\n7")))", but it would be more elegant todo this via Constructor Mocking / Replacing because then i do not have to alter existing code. – Dresel Oct 26 '12 at 12:50
  • It is possible via reflection, see my (Vikram Agrawals) answer below. – Dresel Oct 26 '12 at 13:09
4

It is possible to replace and call a different constructor via reflection:

"Hence, when you are replacing a constructor you should do all your initialization in your constructor. For StreamReader constructor is may not be possible as you don't know how object is internally initialized by original constructor and you don't have access to private members of object.

So, we can use reflection to call in original constructor with to initialized the object and then use it." - See Vikram Agrawals answer on http://social.msdn.microsoft.com

So the code regarding to my question would look like this:

ShimStreamReader.ConstructorString = (@this, value) =>
{
    ConstructorInfo constructor = typeof (StreamReader).GetConstructor(new[] {typeof (Stream)});
    constructor.Invoke(@this, new object[] {new MemoryStream(Encoding.Default.GetBytes("33\r\n1\r\n16\r\n5\r\n7"))});
};
Dresel
  • 2,375
  • 1
  • 28
  • 44