Non-code-generated forwarding shim for testing private methods

烂漫一生 提交于 2019-12-06 11:50:20

问题


In general, I design classes in such a manner as to not require access to privates for testing purposes. An InternalsVisibleTo can also assist.

However, I'm currently dealing with a codebase that has a few area which have become reliant on the [private accessors mechanism in VSTS](http://msdn.microsoft.com/en-us/library/ms184807(VS.80).aspx) (i.e., using VSCodeGenAccessors to generate *_Accessor classes which have forwarding that use reflection to invoke private members (and optionally internal ones too) on a class.

So I've got code like:

ClassUnderTest target = new ClassUnderTest();
var accessor = ClassUnderTest_Accessor.AttachShadow( target );
accessor.PrivateMethod();
Assert.True( accessor._privateMethodWasCalled);
accessor.PrivateProperty = 5;
Assert.Equal( accessor.PrivateProperty, 5);

(Yes, riddled with antipatterns - but please dont shoot the messenger)

I have a number of problems with this:

  1. I'd like to be able to clarify which I privates I need
  2. I'd prefer not to be invoking dialogs (Yes, I'm a CRaholic)
  3. I'd prefer not to involve code generation in the picture

So I'd like to be able to transform the above code to something like:

var target = new ClassUnderTest();
IClassUnderTestInterface accessor = Shadow.Create<IClassUnderTestInterface>( target );
accessor.PrivateMethod();
Assert.True( accessor._privateMethodWasCalled);
accessor.PrivateProperty = 5;
Assert.Equal( accessor.PrivateProperty, 5);

With only the following interface sitting in my test assembly, and no generated code or custom build steps :-

interface IClassUnderTestInterface
{
   int PrivateProperty {get; set;}
   bool _privateMethodWasCalled {get; }
   void PrivateMethod();
}

From there, I'd be able to use CodeRush or Ctrl K M to generate new shadow methods onto the interface with only a keystroke.

The missing bit would be having a method I Shadow.Create<I>( Object o) which would 1. generate a dynamic proxy that implements the interface 1. verify that the object o to be wrapped has all the members dictated by the interface 1. bnous: manage the forwarding of properties representing fields (i.e., the `_privateMethodWasCalled' case) correctly

So, does anyone know a library that implements something like this (or feel bored enough to write it?)

One obvious drawback is that youo dont know if the interface isnt commpatible with the ClassUnderTest until runtime, but that's OK as this would only be for tests. Also AIUI, the private accessors mechanism also requires the triggering of a recompile to sync stuff up from time to time.

Or is there a way better approach I'm missing? (Remembering I dont want to go blanket ugrading al privates to internal or public and dont want to have to rewrite working code)

Using xUnit.net, .NET 3.5; Open to using any dynamic proxy library or other


回答1:


Have you looked at mocking frameworks like Moq or Rhino? In your case they could help IF you are willing to change the privates that your need to test to 'protected virtual' (which is not as bad a going public of internal). Basically, if the member is virtual, then mocking framework can generate a subclass that records what members are called.




回答2:


I ended up routing around all this stuff (InternalsVisibleTo, separate test projects, Test References, private accessors, the MSBuild Shadow task / publicize.exe failing randomly in builds, using reflection to access privates) by merging the tests into the main projects and making anything that needed to be accessed from tests internal). See also xUnit.net Test Stripper [to remove test code embedded in binaries prior to deployment/shipping]




回答3:


This neat trick that can make forwarding functions more succint, although its still manual in nature

Also, this answer covers how to handle static members (but requires CLR4 which wasnt in play at the time of my asking and doesn't handle private methods without bringing InternalsVisibleTo into the mix).



来源:https://stackoverflow.com/questions/1043899/non-code-generated-forwarding-shim-for-testing-private-methods

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!