tonerdo / pose

Replace any .NET method (including static and non-virtual) with a delegate

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Shim Asynchronous methods

ashGHub opened this issue · comments

Is there a way to shim asynchronous method?

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

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

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"));

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

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.

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

image

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;
            }
        }
    }

@SWarnberg same... Could you fix it?

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(() => ""));