pose icon indicating copy to clipboard operation
pose copied to clipboard

Shim Asynchronous methods

Open ashGHub opened this issue 6 years ago • 10 comments

Is there a way to shim asynchronous method?

ashGHub avatar Aug 08 '18 08:08 ashGHub

@ashGHub, I believe shimming asynchronous methods should be the same as normal methods. Have you tried this and did it throw an error?

tonerdo avatar Aug 11 '18 15:08 tonerdo

I tried the following code

public class UnitTest1
{
    [Fact]
    public void Test1()
    {
        HttpClient httpClient = new HttpClient();

        Shim myClassShim = Shim.Replace(() => httpClient.GetStringAsync(Is.A<string>())).With
             (HttpClient @this) => throw new Exception("TEST EXCEPTION"));

         PoseContext.Isolate(() =>
         {
               var url = "DUMMY URL";
              
               Func<Task> action = async () => { await httpClient.GetStringAsync(url); };

               action.Should().Throw<Exception>()
                     .WithMessage("TEST EXCEPTION");
         });
     }
}

But the test won't pass the the shim setup for GetStringAsync. It is throwing Message: Pose.Exceptions.InvalidShimSignatureException : Mismatched return types

To reproduce this;

  1. Create an xUnit test project using .net core 2.1.
  2. Add a nuget package FluentAssertions.
  3. Use the above code

FYI:

I tried to replace the shim with

Shim myClassShim = Shim.Replace(() => httpClient.GetStringAsync(Is.A<string>())).With(
                (HttpClient @this) => Task.Factory.StartNew(() => throw new Exception("TEST EXCEPTION")));

Still, it is throwing the same exception.

Thanks

ashGHub avatar Aug 14 '18 06:08 ashGHub

Because of how delegates are setup the runtime is interpreting your replacement delegate as void by default. I suggest you try returning a dummy Task<string> value.

If you really need to throw an exception, you can try the following:

Task.Factory.StartNew<string>(() => throw new Exception("TEST EXCEPTION"));

tonerdo avatar Aug 15 '18 10:08 tonerdo

I used what you've suggested and this error showed up Message: Pose.Exceptions.InvalidShimSignatureException : Parameters count do not match

ashGHub avatar Aug 17 '18 07:08 ashGHub

It doesn't work for me either. Imagine a test scenario where you're testing a ViewModel that contains an async command, which in turn executes an async call to a component that you want to shim. For me it gives the following exception:

System.Reflection.TargetInvocationException
  HResult=0x80131604
  Message=Exception has been thrown by the target of an invocation.
  Source=System.Private.CoreLib
  StackTrace:
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor, Boolean wrapExceptions)
   at System.Reflection.RuntimeMethodInfo.Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)
   at System.Delegate.DynamicInvokeImpl(Object[] args)
   at Pose.PoseContext.Isolate(Action entryPoint, Shim[] shims)

Inner Exception 1:
InvalidProgramException: Common Language Runtime detected an invalid program.

SWarnberg avatar Aug 31 '18 07:08 SWarnberg

Sorry, I am trying to mock static method but I want simulate that this call throws a particular exception.

image

dm-conti avatar Apr 10 '19 08:04 dm-conti

Hi, I'am new of C# and .NET framework. My solution for static methods is:

    [TestMethod]
    [ExpectedException(typeof(TimeoutException), "Dummy Time Out Exception")]
    public void Test_MockStaticMethod_MethodMocked_AndThrowTimeoutException()
    {
        Func<string> myFunc = delegate ()
        {
            throw new TimeoutException();
        };

        Shim consoleShim = Shim.Replace(() => MyItem.GetStaticSession()).With(myFunc);
        try
        {
            PoseContext.Isolate(() =>
            {
                MyItem.GetStaticSession();
            }, consoleShim);
        }
        catch (Exception ex)
        {
            if (ex.InnerException != null && ex.InnerException is TimeoutException) {
                throw ex.InnerException;
            }
        }
    }

dm-conti avatar Apr 12 '19 14:04 dm-conti

@SWarnberg same... Could you fix it?

OscarCanek avatar May 22 '19 18:05 OscarCanek

Have a similar problem, some solution @tonerdo?

var shim = Shim
    .Replace(() => Is.A<IDbConnection>().QueryFirstOrDefaultAsync<string>(
        Is.A<string>(),
        Is.A<object>(),
        Is.A<IDbTransaction>(),
        Is.A<int?>(),
        Is.A<CommandType?>()))
    .With(() => Task.Factory.StartNew(() => ""));

MariuszPL55 avatar May 23 '19 13:05 MariuszPL55

For support for async/await please see https://github.com/Miista/pose/issues/12

cc: @tonerdo @ashGHub @SWarnberg @dm-conti @OscarCanek @MariuszPL55 @alexzaytsev-newsroomly @ydemetriades @qjnz @NecromancerKing @lpatterson14

Miista avatar Jan 27 '24 20:01 Miista