locked
MSFakes : Shim class for a method with more than 2 out argument RRS feed

  • Question

  • All,

    I am writing unit tests using MS Fakes for a class that has methods with more than 4 arguments.

    I find that the Shim class created for those methods are missing from the AllInstances property. I see that it has got those other methods which have less than 1 out arguments. These methods are just public methods on the class. Why the Shim class is missing those methods and is there a work around for that scenario?

    To preproduce this scenario, create a class like this:

    I tried methods that take up to 6 arguments and methods with multiple out arguments.

    public class TestFakes {

    //........

    public bool SixArgumentMethod(int i1, int i2, int i3, int i4, int i5, int i6) { return true; } public bool OneOutArgumentsMethod(int i1, out int i2) { i2 = 0; return true; } public bool TwoOutArgumentsMethod(int i1, out int i2, out int i3) { i2 = 0; i3 = 0; return true; } public bool ThreeOutArgumentsMethod(int i1, out int i2, out int i3, out int i4) { i2 = 0; i3 = 0; i4 = 0; return true; } }

    The Shim class works fine for as many input arguments, but it fails for methods that has more than 2 out arguments.

    For example, the generated Shim class generated for this class is missing method : ThreeOutArgumentsMethod() but covers OneOutArgumentsMethod() and TwoOutArgumentsMethod().

    public class ShimTestFakes : ShimBase<TestFakes>
    {
      //....only including relevant code...
            public static class AllInstances
            {
                // Summary:
                //     Sets the shim of TestFakes.FiveArgumentMethod(Int32 i1, Int32 i2, Int32 i3,
                //     Int32 i4, Int32 i5)
                public static FakesDelegates.Func<TestFakes, int, int, int, int, int, bool> FiveArgumentMethodInt32Int32Int32Int32Int32 { set; }
                //
                // Summary:
                //     Sets the shim of TestFakes.FourArgumentMethod(Int32 i1, Int32 i2, Int32 i3,
                //     Int32 i4)
                public static FakesDelegates.Func<TestFakes, int, int, int, int, bool> FourArgumentMethodInt32Int32Int32Int32 { set; }
                //
                // Summary:
                //     Sets the shim of TestFakes.OneArgumentMethod(Int32 i1)
                public static FakesDelegates.Func<TestFakes, int, bool> OneArgumentMethodInt32 { set; }
                //
                // Summary:
                //     Sets the shim of TestFakes.OneOutArgumentsMethod(Int32 i1, Int32& i2)
                public static FakesDelegates.OutFunc<TestFakes, int, int, bool> OneOutArgumentsMethodInt32Int32Out { set; }
                //
                // Summary:
                //     Sets the shim of TestFakes.SixArgumentMethod(Int32 i1, Int32 i2, Int32 i3,
                //     Int32 i4, Int32 i5, Int32 i6)
                public static FakesDelegates.Func<TestFakes, int, int, int, int, int, int, bool> SixArgumentMethodInt32Int32Int32Int32Int32Int32 { set; }
                //
                // Summary:
                //     Sets the shim of TestFakes.ThreeArgumentMethod(Int32 i1, Int32 i2, Int32
                //     i3)
                public static FakesDelegates.Func<TestFakes, int, int, int, bool> ThreeArgumentMethodInt32Int32Int32 { set; }
                //
                // Summary:
                //     Sets the shim of TestFakes.TwoArgumentMethod(Int32 i1, Int32 i2)
                public static FakesDelegates.Func<TestFakes, int, int, bool> TwoArgumentMethodInt32Int32 { set; }
                //
                // Summary:
                //     Sets the shim of TestFakes.TwoOutArgumentsMethod(Int32 i1, Int32& i2, Int32&
                //     i3)
                public static FakesDelegates.OutOutFunc<TestFakes, int, int, int, bool> TwoOutArgumentsMethodInt32Int32OutInt32Out { set; }
            }

    Is this a known limitation with Fakes?

    What is the work around for this?

    Thanks!



    Tuesday, May 28, 2013 4:50 PM

Answers

  • Update on this issue.

    This is not an issue with Shim class only, but with Stub class too. If you take a look at the Stun class generated, it has none of the methods that TestFakes class is having.

    public class StubTestFakes : TestFakes, IStub<TestFakes>, IStubObservable, IPartialStub, IStub
        {
            // Summary:
            //     Initializes a new instance
            public StubTestFakes();
    
            // Summary:
            //     Gets or sets a value that indicates if the base method should be called instead
            //     of the fallback behavior
            public bool CallBase { get; set; }
            //
            // Summary:
            //     Gets or sets the instance behavior.
            public IStubBehavior InstanceBehavior { get; set; }
            //
            // Summary:
            //     Gets or sets the instance observer.
            public IStubObserver InstanceObserver { get; set; }
        }

    I found a work around by having an interface for the above class.

     public interface ITestFakes
        {
            bool SixArgumentMethod(int i1, int i2, int i3, int i4, int i5, int i6);
            bool OneOutArgumentsMethod(int i1, out int i2);
            bool TwoOutArgumentsMethod(int i1, out int i2, out int i3);
            bool ThreeOutArgumentsMethod(int i1, out int i2, out int i3, out int i4);
        }

    Now you can see that the Stub class generated for this interface has got all the methods.

    public class StubITestFakes : StubBase<ITestFakes>, ITestFakes
        {
            // Summary:
            //     Sets the stub of ITestFakes.OneOutArgumentsMethod(Int32 i1, Int32& i2)
            public FakesDelegates.OutFunc<int, int, bool> OneOutArgumentsMethodInt32Int32Out;
            //
            // Summary:
            //     Sets the stub of ITestFakes.SixArgumentMethod(Int32 i1, Int32 i2, Int32 i3,
            //     Int32 i4, Int32 i5, Int32 i6)
            public FakesDelegates.Func<int, int, int, int, int, int, bool> SixArgumentMethodInt32Int32Int32Int32Int32Int32;
            //
            // Summary:
            //     Sets the stub of ITestFakes.ThreeOutArgumentsMethod(Int32 i1, Int32& i2,
            //     Int32& i3, Int32& i4)
            public FakesDelegates.Out1Out2Out3Func5<int, int, int, int, bool> ThreeOutArgumentsMethodInt32Int32OutInt32OutInt32Out;
            //
            // Summary:
            //     Sets the stub of ITestFakes.TwoOutArgumentsMethod(Int32 i1, Int32& i2, Int32&
            //     i3)
            public FakesDelegates.OutOutFunc<int, int, int, bool> TwoOutArgumentsMethodInt32Int32OutInt32Out;
    
            // Summary:
            //     Initializes a new instance of type StubITestFakes
            public StubITestFakes();
        }

    So now I can have my fake for the interface implemented as follows.

    var myFake = new MyServices.Fakes.StubITestFakes
                        {
                            TwoOutArgumentsMethodInt32Int32OutInt32Out =
                            (int i1, out int i2, out int i3) =>
                            {
                                i2 = 0;
                                i3 = 0;
                                return true;
                            }
                        };

    I wish I didn't have to take this long route.

    Any suggestions?


    Tuesday, May 28, 2013 5:33 PM

All replies

  • Update on this issue.

    This is not an issue with Shim class only, but with Stub class too. If you take a look at the Stun class generated, it has none of the methods that TestFakes class is having.

    public class StubTestFakes : TestFakes, IStub<TestFakes>, IStubObservable, IPartialStub, IStub
        {
            // Summary:
            //     Initializes a new instance
            public StubTestFakes();
    
            // Summary:
            //     Gets or sets a value that indicates if the base method should be called instead
            //     of the fallback behavior
            public bool CallBase { get; set; }
            //
            // Summary:
            //     Gets or sets the instance behavior.
            public IStubBehavior InstanceBehavior { get; set; }
            //
            // Summary:
            //     Gets or sets the instance observer.
            public IStubObserver InstanceObserver { get; set; }
        }

    I found a work around by having an interface for the above class.

     public interface ITestFakes
        {
            bool SixArgumentMethod(int i1, int i2, int i3, int i4, int i5, int i6);
            bool OneOutArgumentsMethod(int i1, out int i2);
            bool TwoOutArgumentsMethod(int i1, out int i2, out int i3);
            bool ThreeOutArgumentsMethod(int i1, out int i2, out int i3, out int i4);
        }

    Now you can see that the Stub class generated for this interface has got all the methods.

    public class StubITestFakes : StubBase<ITestFakes>, ITestFakes
        {
            // Summary:
            //     Sets the stub of ITestFakes.OneOutArgumentsMethod(Int32 i1, Int32& i2)
            public FakesDelegates.OutFunc<int, int, bool> OneOutArgumentsMethodInt32Int32Out;
            //
            // Summary:
            //     Sets the stub of ITestFakes.SixArgumentMethod(Int32 i1, Int32 i2, Int32 i3,
            //     Int32 i4, Int32 i5, Int32 i6)
            public FakesDelegates.Func<int, int, int, int, int, int, bool> SixArgumentMethodInt32Int32Int32Int32Int32Int32;
            //
            // Summary:
            //     Sets the stub of ITestFakes.ThreeOutArgumentsMethod(Int32 i1, Int32& i2,
            //     Int32& i3, Int32& i4)
            public FakesDelegates.Out1Out2Out3Func5<int, int, int, int, bool> ThreeOutArgumentsMethodInt32Int32OutInt32OutInt32Out;
            //
            // Summary:
            //     Sets the stub of ITestFakes.TwoOutArgumentsMethod(Int32 i1, Int32& i2, Int32&
            //     i3)
            public FakesDelegates.OutOutFunc<int, int, int, bool> TwoOutArgumentsMethodInt32Int32OutInt32Out;
    
            // Summary:
            //     Initializes a new instance of type StubITestFakes
            public StubITestFakes();
        }

    So now I can have my fake for the interface implemented as follows.

    var myFake = new MyServices.Fakes.StubITestFakes
                        {
                            TwoOutArgumentsMethodInt32Int32OutInt32Out =
                            (int i1, out int i2, out int i3) =>
                            {
                                i2 = 0;
                                i3 = 0;
                                return true;
                            }
                        };

    I wish I didn't have to take this long route.

    Any suggestions?


    Tuesday, May 28, 2013 5:33 PM
  • Hi Sudheer,

    Thank you for sharing your solutions here. It will be very beneficial for other community members who have similar questions. I mark your reply as the answer.

    Best Regards,


    Jack Zhai [MSFT]
    MSDN Community Support | Feedback to us
    Develop and promote your apps in Windows Store
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    Thursday, May 30, 2013 5:14 AM
  • Another note while designing for testability.

    If you have more than 2 argument, better consider returning a complex type as return type and have all of your required out fields over there.

    That way you can continue using Shims and don't have to work around.

    Tuesday, June 25, 2013 5:51 PM
  • Sudheer,

    This is a Fakes limitation in Visual Studio 2012. The Fakes code generator uses a limited number of predefined delegate types defined in FakesDelegates. It includes delegate types for as many common method signatures as we could think of. However, with the infinite number of possible combination of ref and out parameters, there are many signatures it does not support.

    In Visual Studio 2013, we addressed this problem by changing the Fakes code generator to generate a custom delegate type directly in the fakes assembly instead of relying on just the pre-defined types.

    Hope this helps.

    Thursday, June 27, 2013 4:49 PM