Friday, April 15, 2011

Quick question on reflection in C#

I am getting started with the notion of test-driven development, and kind of failing since I am finding that I know what the test is going to be kind of, but I can't figure out how to get it to do what I want. What I have is a property that has a public getter and an internal setter. I'd like to test the functionality by accessing the internal setter from the unit test, but I can't figure out just how to do it. Here is the test:

 [Test()]
 public void HandleInput() {
  _requestType = _request.GetType();
  PropertyInfo propStdin =
   _requestType.GetProperty("StandardInput", BindingFlags.Public | BindingFlags.NonPublic);
  if(propStdin == null) {
   // Bug in the test.
   throw new Exception("There is a bug in the test. Reflection of stdin property returned null.");
  }
  MethodInfo setStdin = propStdin.GetSetMethod();

  // This will fail at the moment since nothing is here to make this happen.
  Assert.AreEqual("NewInputNewRequestInput", _request.StandardInput);
 }

Now, the problem is that when I run the test, I get:

[mono-2.4] mbt@zest:~/Projects/StaffASAP/Test.FastCGI/bin/Debug$ nunit-console2 Test.FastCGI.dll
NUnit version 2.4.8
Copyright (C) 2002-2007 Charlie Poole.
Copyright (C) 2002-2004 James W. Newkirk, Michael C. Two, Alexei A. Vorontsov.
Copyright (C) 2000-2002 Philip Craig.
All Rights Reserved.

Runtime Environment - 
   OS Version: Unix 2.6.29.0
  CLR Version: 2.0.50727.1433 ( Mono 2.4 )

..F
Tests run: 2, Failures: 1, Not run: 0, Time: 0.111 seconds

Test Case Failures:
1) Test.FastCGI.tRequest.HandleInput : System.Exception : There is a bug in the test. Reflection of stdin property returned null.
at Test.FastCGI.tRequest.HandleInput () [0x00051] in /home/mbt/Projects/StaffASAP/Test.FastCGI/tRequest.cs:54
at (wrapper managed-to-native) System.Reflection.MonoMethod:InternalInvoke (object,object[],System.Exception&)
at System.Reflection.MonoMethod.Invoke (System.Object obj, BindingFlags invokeAttr, System.Reflection.Binder binder, System.Object[] parameters, System.Globalization.CultureInfo culture) [0x00057] in /media/disk/mono-2.4/sources/mono-2.4/mcs/class/corlib/System.Reflection/MonoMethod.cs:159

So, I must be attempting to access the property incorrectly, but from looking at the documentation, I don't know what I am doing wrong. What am I doing wrong?

From stackoverflow
  • You may want to look at the InternalsVisibleTo assembly attribute:

    [Y]ou can expose an assembly's internal methods/properties/classes to a "friend" assembly. Normally internals are only accessible to members of the same assembly, and are often used to hide "plumbing" methods and utilities classes.

  • Here is a similar article on SO that deals with Unit tests, internal members and reflection..

  • Are you missing | BindingFlags.Instance in the GetProperty(...) call?

    It would be much nicer however to expose the internal variables to the test program through the InternalsVisibleTo attribute, as you don't need to rely on reflection, and refactoring will propagate if the test project is part of your solution in Visual Studio.

    Michael Trausch : Thanks for the additional pointer to BindingFlags.Instance. That works, as does the InternalsVisibleTo attribute. I've gone with using the InternalsVisibleTo attribute since it makes the tests easier to write and more readable, but the other info is great, too!
    Cecil Has a Name : While reflection is interesting and powerful, you'll find it is picky about the details.

0 comments:

Post a Comment