Code Monkey home page Code Monkey logo

Comments (15)

tonerdo avatar tonerdo commented on May 22, 2024 3

I've noticed that Assert statements tend to break Pose. I'm currently looking into it, but in the meantime you can do this instead:

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Pose.Tests.Fails
{
    [TestClass]
    public class ShimFails
    {
        public class MyClass
        {
            public int MyProperty { get; set; }
        }

        [TestMethod]
        [ExpectedException(typeof(NullReferenceException))]
        public void ShimConstructor()
        {
            Shim ctorShim = Shim.Replace(() => new MyClass())
                .With(() => new MyClass { MyProperty = 10 });
            
            int prop = 0;

            PoseContext.Isolate(() =>
            {
                prop = new MyClass().MyProperty;
            }, ctorShim);

            // this line breaks the Shim
            Assert.AreEqual(10, prop);
        }
    }
}

from pose.

tonerdo avatar tonerdo commented on May 22, 2024

@tjrobinson if the client test actually calls the code in the controller instead of making an actual http request you should be fine. I'm looking into this as well as the other issues you raised. Have you been able to get some other tests to work with Pose?

from pose.

tonerdo avatar tonerdo commented on May 22, 2024

Also what's happening here is that a stub is passing a null method to be rewritten.

from pose.

tjrobinson avatar tjrobinson commented on May 22, 2024

if the client test actually calls the code in the controller instead of making an actual http request you should be fine

Yep, I think it would be. Unfortunately these are deliberate integration tests to check the API layer. I have other tests for the MediatR commands/queries that the controllers use.

I haven't got any other tests working with Pose yet as I've not tried yet.

from pose.

tonerdo avatar tonerdo commented on May 22, 2024

Alrighty. Do try if/when you can and let me know if you run into anymore problems. Thanks

from pose.

tonerdo avatar tonerdo commented on May 22, 2024

@tjrobinson I'm curious, what made you think the error was from Pose.Helpers.StubHelper.GetMatchingShimIndex? The exception stack trace doesn't include it. Also I notice you're using Pose directly in source code form, you can update your local with this branch https://github.com/tonerdo/pose/tree/stub-enhancements and try the code again. Paste the exception output here, I added a few things to make it easier to track the origin of exceptions like this

from pose.

tjrobinson avatar tjrobinson commented on May 22, 2024

@tonerdo GetMatchingShimIndex was coming up in the stack trace when I was trying a few things out earlier on though as you noticed, it's not in the one above. I think it's a different trace because I tried to simplify the failing scenario and ended up with a variation on the problem. Sorry I don't have the earlier stack trace anymore.

I can't try the stub-enhancements branch at the moment but will if I get time at some other point .

from pose.

jonkeda avatar jonkeda commented on May 22, 2024

@tonerdo I have the same Null Reference Exception popping up. And tracked it down to GetRuntimeMethodForVirtual

The following code throws the null reference exception.

using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace Pose.Tests.Fails
{
    [TestClass]
    public class ShimFails
    {
        public class MyClass
        {
            public int MyProperty { get; set; }
        }

        [TestMethod]
        [ExpectedException(typeof(NullReferenceException))]
        public void ShimConstructor()
        {
            Shim ctorShim = Shim.Replace(() => new MyClass())
                .With(() => new MyClass { MyProperty = 10 });

            PoseContext.Isolate(() =>
            {
                // this line breaks the Shim
                Assert.AreEqual(10, 10);

            }, ctorShim);
        }

    }
}

It was trying to find: RuntimeType.GetTypeInfo but the actual method name was System.Reflection.TypeInfo.System.Reflection.IReflectableType.GetTypeInfo(). I tried to return that but it didn't seem to help.

After that I was getting confused.

Hope this helps.

from pose.

jonkeda avatar jonkeda commented on May 22, 2024

I tried looking into the issue. Unfortunately I haven't found a solution yet. I tried the following:

  1. The RuntimeMethodForVirtual returns null after which GetIndexOfMatchingShim will fail.
    In the Assert case Type is System.RunTimeType and methodInfo is GetTypeInfo
        public static MethodInfo GetRuntimeMethodForVirtual(Type type, MethodInfo methodInfo)
        {
            BindingFlags bindingFlags = BindingFlags.Instance | (methodInfo.IsPublic ? BindingFlags.Public : BindingFlags.NonPublic);
            Type[] types = methodInfo.GetParameters().Select(p => p.ParameterType).ToArray();
            return type.GetMethod(methodInfo.Name, bindingFlags, null, types, null);
        }

  1. One solution I tried was to find the method in anotherway. ie:
        public static MethodInfo GetRuntimeMethodForVirtual(Type type, MethodInfo methodInfo)
        {
            BindingFlags bindingFlags = BindingFlags.Instance | (methodInfo.IsPublic ? BindingFlags.Public : BindingFlags.NonPublic);
            Type[] types = methodInfo.GetParameters().Select(p => p.ParameterType).ToArray();
            MethodInfo foundMethod = type.GetMethod(methodInfo.Name, bindingFlags, null, types, null);
            if (foundMethod == null)
            {
                MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
                foundMethod = methods.FirstOrDefault(i => i.Name.EndsWith(methodInfo.Name));
                return foundMethod;
            }
            return foundMethod;
        }

The name of the method it find is: "System.Reflection.IReflectableType.GetTypeInfo" (this is not the FullName, but the normal Name.

But running this results in crashing the debugger.

  1. Next I tried to simply run the original method whenever RuntimeMethodForVirtual returned NULL but I that resulted in a invalid program.

from pose.

Daxaker avatar Daxaker commented on May 22, 2024

@jonkeda Problem with Assert.AreEqual caused by explicit implementation of IReflectableType.GetTypeInfo() in

class System.Reflection.IntrospectionExtensions
{
  public static TypeInfo GetTypeInfo(this Type type)
  {
    if (type == (Type) null)
      throw new ArgumentNullException(nameof (type));
    return ((IReflectableType) type).GetTypeInfo();
   }
}

this is the reason why
public static MethodInfo GetRuntimeMethodForVirtual(Type type, MethodInfo methodInfo)
returns null

there is a case to reproduce this issue

interface IMyTest
{
   int ExplicitMethod();
}

class MyTest : IMyTest
{
   int IMyTest.ExplicitMethod() => 1;
}

[TestMethod]
public void TestExplicit()
{
    Shim shim = Shim.Replace(() => Is.A<IMyTest>().ExplicitMethod()).With((IMyTest t) => 42);
    var r =  new MyTest();
    PoseContext.Isolate(() => { var foo = ((IMyTest)r).ExplicitMethod(); }, shim);
 }

I haven't solve this problem yet but if your know an elegant and easy way to get explicitly implemented members, i would like to hear about it

from pose.

jonkeda avatar jonkeda commented on May 22, 2024

@Daxaker It isn't anywere near elegant, but I do have a working 'solution'.

  1. if the method isn't found then look if a method exists which name ends with the method to find. (brrr)
        public static MethodInfo GetRuntimeMethodForVirtual(Type type, MethodInfo methodInfo)
        {
            BindingFlags bindingFlags = BindingFlags.Instance | (methodInfo.IsPublic ? BindingFlags.Public : BindingFlags.NonPublic);
            Type[] types = methodInfo.GetParameters().Select(p => p.ParameterType).ToArray();
            var method = type.GetMethod(methodInfo.Name, bindingFlags, null, types, null);
            if (method == null)
            {
                MethodInfo[] methods = type.GetMethods(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
                MethodInfo foundMethod = methods.FirstOrDefault(i => i.Name.EndsWith(methodInfo.Name));
                return foundMethod;
            }
            return method;
        }
  1. Expand the SignatureEquals to also look for interfaces.
    private static bool SignatureEquals(Shim shim, Type type, MethodBase method)
        {
            if (shim.Type == null || type == shim.Type)
                return $"{shim.Type}::{shim.Original.ToString()}" == $"{type}::{method.ToString()}";

            if (type.IsSubclassOf(shim.Type))
            {
                if ((shim.Original.IsAbstract || !shim.Original.IsVirtual)
                        || (shim.Original.IsVirtual && !method.IsOverride()))
                {
                    return $"{shim.Original.ToString()}" == $"{method.ToString()}";
                }
            }

            if (shim.Type.IsAssignableFrom(type))
            {
                if ((shim.Original.IsAbstract || !shim.Original.IsVirtual)
                    || (shim.Original.IsVirtual && !method.IsOverride()))
                {
                    return $"{shim.Original.ToString()}" == $"{method.ToString()}"
                        || method.Name.EndsWith(shim.Original.Name) ;
                }
            }

            return false;
        }

This code works for your testcase. But isn't very elegant or fail safe.

from pose.

tonerdo avatar tonerdo commented on May 22, 2024

@Daxaker many thanks for this repro. Will take a look and work on a fix

from pose.

Daxaker avatar Daxaker commented on May 22, 2024

@tonerdo Glad to be helpful

from pose.

brian-pickens avatar brian-pickens commented on May 22, 2024

My issue indeed had to do with calling xUnit Assert() method within the Isolate() function. Moving my assert methods out fixed the error for me.

from pose.

StarkShang avatar StarkShang commented on May 22, 2024

Has this problem fixed in a new distribution?
Or is it a normative way to act in isolate context and to assert outside?

from pose.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.