Search code examples
c#moqvs-unit-testing-frameworkprivateobject.invoke

Is Moq incompatible with PrivateObject?


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?


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.