Question

I'm trying to test a private method on a mocked object. Please, calm down, I know you're getting your pitchforks out.

I'm well aware everything about to say can be answered by yelling REFACTOR at me. I just need a straight answer. Someone look me in the eyes and tell me this can't be done. It's an ungoogleable problem, so I just need to hear it.

Here's what I'm dealing with.

public class SecretManager
{
   protected virtual string AwfulString { get { return "AWFUL, AWFUL THING"; }

   public SecretManager()
   {
      //do something awful that should be done using injection
   }

   private string RevealSecretMessage()
   {
      return "don't forget to drink your ovaltine";
   }
}

Here's me trying to test it.

var mgr = new Mock<SecretManager>();
mgr.Protected().SetupGet<string>("AwfulThing").Returns("");

var privateObj = new PrivateObject(mgr.Object);
string secretmsg = privateObj.Invoke("RevealSecretMessage");

Assert.IsTrue(secretmsg.Contains("ovaltine"));

and the exception:

System.MissingMethodException: Method 'Castle.Proxies.SecretManagerProxy.RevealSecretMessage' not found

Is what I'm trying to do, mad as it is, possible? Or is this simply too much hubris for a unit test to bear?

Was it helpful?

Solution

You're trying to call a method on the proxy that Castle created. The proxy won't have access to the private method on the class that it inherits from because, well, the method is private. Remember that Castle.Proxies.SecretManagerProxy is actually a subclass of SecretManager.

Do you really need a mock of SecretManager? I realize your code is a slimmed down abstract of the real code, but it seems the only thing you're doing with the mock is setting up a return for a property that isn't used by the method you're trying to test anyway.

OTHER TIPS

var privateObj = new PrivateObject(mgr.Object, new PrivateType(typeof(SecretManager)));
string secretmsg = privateObj.Invoke("RevealSecretMessage");

It will work by specifying PrivateType for the PrivateObject.

Your code should be following for what you are trying to test. You don't need to mock the SecretManager and SetGet "AwfulThing" as you are not using it.

var privateObj = new PrivateObject(new SecretManager());
string secretmsg = (string)privateObj.Invoke("RevealSecretMessage", new object[] {     });

Assert.IsTrue(secretmsg.Contains("ovaltine"));

But ideally you shouldn't be testing Private methods. See below article for the explanation:

http://lassekoskela.com/thoughts/24/test-everything-but-not-private-methods/

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top