pose icon indicating copy to clipboard operation
pose copied to clipboard

Null Reference Exception when Replacing ShowDialog() on a WinForm

Open johnkoerner opened this issue 6 years ago • 6 comments

I was playing with Pose and ran into a null reference exception when trying to replace the ShowDialog method on a Windows Form.

This is a .net 4.6.1 assembly using MSTest as the test runner.

The code under test is:

public class FormShower
{
    public void ShowTheForm()
    {
        Form1 f = new Form1();
        f.ShowDialog();
    }
}

The Test code is

Shim s = Shim.Replace(() => Is.A<PosePlayground.Form1>().ShowDialog())
            .With(delegate (Form1 @this) { Console.WriteLine("hello"); return DialogResult.OK; });

FormShower fs = new FormShower();
PoseContext.Isolate(() =>
{
    fs.ShowTheForm();
}, s);

Using this code, I get the following exception:

Result StackTrace:	
at Pose.Helpers.StubHelper.GetIndexOfMatchingShim(MethodBase methodBase, Type type, Object obj)
   at stub_virt_System.Configuration.Internal.IInternalConfigSystem_GetSection(IInternalConfigSystem , String , RuntimeMethodHandle , RuntimeTypeHandle )
   at dynamic_System.Configuration.ConfigurationManager_GetSection(String )
   at stub_System.Configuration.ConfigurationManager_GetSection(String , RuntimeMethodHandle , RuntimeTypeHandle )
   at dynamic_System.Configuration.ConfigurationManager_get_AppSettings()
   at stub_System.Configuration.ConfigurationManager_get_AppSettings(RuntimeMethodHandle , RuntimeTypeHandle )
   at dynamic_System.Windows.Forms.DpiHelper_Initialize()
   at stub_System.Windows.Forms.DpiHelper_Initialize(RuntimeMethodHandle , RuntimeTypeHandle )
   at dynamic_System.Windows.Forms.DpiHelper_InitializeDpiHelperForWinforms()
   at stub_System.Windows.Forms.DpiHelper_InitializeDpiHelperForWinforms(RuntimeMethodHandle , RuntimeTypeHandle )
   at dynamic_System.Windows.Forms.Control_.ctor(Control , Boolean )
   at stub_ctor_System.Windows.Forms.Control_.ctor(Control , Boolean , RuntimeMethodHandle , RuntimeTypeHandle )
   at dynamic_System.Windows.Forms.Control_.ctor(Control )
   at stub_ctor_System.Windows.Forms.Control_.ctor(Control , RuntimeMethodHandle , RuntimeTypeHandle )
   at dynamic_System.Windows.Forms.ScrollableControl_.ctor(ScrollableControl )
   at stub_ctor_System.Windows.Forms.ScrollableControl_.ctor(ScrollableControl , RuntimeMethodHandle , RuntimeTypeHandle )
   at dynamic_System.Windows.Forms.ContainerControl_.ctor(ContainerControl )
   at stub_ctor_System.Windows.Forms.ContainerControl_.ctor(ContainerControl , RuntimeMethodHandle , RuntimeTypeHandle )
   at dynamic_System.Windows.Forms.Form_.ctor(Form )
   at stub_ctor_System.Windows.Forms.Form_.ctor(Form , RuntimeMethodHandle , RuntimeTypeHandle )
   at dynamic_PosePlayground.Form1_.ctor(Form1 )
   at stub_ctor_PosePlayground.Form1_.ctor(RuntimeMethodHandle , RuntimeTypeHandle )
   at dynamic_PosePlayground.FormShower_ShowTheForm(FormShower )
   at stub_virt_PosePlayground.FormShower_ShowTheForm(FormShower , RuntimeMethodHandle , RuntimeTypeHandle )
   at dynamic_UnitTestProject1.UnitTest1+<>c__DisplayClass0_0_<TestMethod1>b__2(<>c__DisplayClass0_0 )
--- End of inner exception stack trace ---
    at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)
   at System.Reflection.RuntimeMethodInfo.UnsafeInvokeInternal(Object obj, Object[] parameters, Object[] arguments)
   at System.Delegate.DynamicInvokeImpl(Object[] args)
   at Pose.PoseContext.Isolate(Action entryPoint, Shim[] shims)
   at UnitTestProject1.UnitTest1.TestMethod1() in C:\Users\koernej\source\repos\PosePlayground\UnitTestProject1\UnitTest1.cs:line 18
Result Message:	
Test method UnitTestProject1.UnitTest1.TestMethod1 threw exception: 
System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.NullReferenceException: Object reference not set to an instance of an object.

If I replace the constructor of Form1 then everything works as expected.

Shim ctorShim = Shim.Replace(() => new Form1()).With(() => new Form1());

Is this expected? I am currently evaluating pose as a replacement to an existing isolation/replacement testing framework and I am trying to understand the basic use cases and how we can migrate our code if it fits our needs.

johnkoerner avatar Jan 23 '18 14:01 johnkoerner

This may be related to #11 as the stack traces are similar.

johnkoerner avatar Jan 23 '18 15:01 johnkoerner

Hey @johnkoerner. Thanks for reporting these issues. Most of these problems is as a result of incorrect MSIL generated during the rewriting of a method. I'm currently working on an under the hood re-implementation of Pose that replaces IL generation with Expression Trees which should fix most of the issues with Pose as well as open up more features like breakpoint support etc.

This re-implementation should be rolling out in about a week or two, but in the meantime I'll take a look at fixing this issue.

tonerdo avatar Jan 24 '18 09:01 tonerdo

Thanks for the update @tonerdo . When you feel it is ready, let me know and I can pull a branch and build it to test it out.

johnkoerner avatar Jan 25 '18 16:01 johnkoerner

@tonerdo we, as a community, are looking forward to see the new implementation! If you need any help, feel free to ask.

ForNeVeR avatar Jan 29 '18 14:01 ForNeVeR

Any update on the new implementation? I am getting this same exception when trying to use Pose in conjunction with Moq.

SamerAdra avatar Oct 17 '18 17:10 SamerAdra

I believe I'm experiencing this exception too. For me, changing the last line of GetRuntimeMethodForVirtual, in StubHelper.cs, to

return type.GetMethod(methodInfo.Name, bindingFlags, null, types, null) ??
    type.GetMethod($"{methodInfo.DeclaringType.FullName}.{methodInfo.Name}", BindingFlags.Instance | BindingFlags.NonPublic, null, types, null);

did the trick.

My analysis is that, without this change, GetRuntimeMethodForVirtual does not know how to handle explicit interface implementations.

VB.NET's Implements keyword may cause similar problems; I've never checked out what they look like under the hood.

DaleStan avatar Aug 20 '19 14:08 DaleStan