views:

200

answers:

2

I am working on mocking some external dependencies and am having trouble with one 3rd party class that takes in it's constructor an instance of another 3rd party class. Hopefully the SO community can give me some direction.

I want to create a mock instance of SomeRelatedLibraryClass that takes in it's constructor a mock instance of SomeLibraryClass. How can I mock SomeRelatedLibraryClass this way?

The repo code...

Here is a Main method that I am using in my test console application.

public static void Main()
{
    try
    {
        SomeLibraryClass slc = new SomeLibraryClass("direct to 3rd party");
        slc.WriteMessage("3rd party message");
        Console.WriteLine();

        MyClass mc = new MyClass("through myclass");
        mc.WriteMessage("myclass message");
        Console.WriteLine();

        Mock<MyClass> mockMc = new Mock<MyClass>("mock myclass");
        mockMc.Setup(i => i.WriteMessage(It.IsAny<string>()))
            .Callback((string message) => Console.WriteLine(string.Concat("Mock SomeLibraryClass WriteMessage: ", message)));

        mockMc.Object.WriteMessage("mock message");
        Console.WriteLine();
    }
    catch (Exception e)
    {
        string error = string.Format("---\nThe following error occurred while executing the snippet:\n{0}\n---", e.ToString());
        Console.WriteLine(error);
    }
    finally
    {
        Console.Write("Press any key to continue...");
        Console.ReadKey();
    }
}

Here is a class that I have used to wrap one third party class and allow it to be Moq'd:

public class MyClass
{
    private SomeLibraryClass _SLC;

    public MyClass(string constructMsg)
    {
        _SLC = new SomeLibraryClass(constructMsg);
    }

    public virtual void WriteMessage(string message)
    {
        _SLC.WriteMessage(message);
    }
}

Here are two examples of 3rd party classes I am working with (YOU CAN NOT EDIT THESE):

public class SomeLibraryClass
{
    public SomeLibraryClass(string constructMsg)
    {
        Console.WriteLine(string.Concat("SomeLibraryClass Constructor: ", constructMsg));
    }

    public void WriteMessage(string message)
    {
        Console.WriteLine(string.Concat("SomeLibraryClass WriteMessage: ", message));
    }
}

public class SomeRelatedLibraryClass
{
    public SomeRelatedLibraryClass(SomeLibraryClass slc)
    {
        //do nothing
    }

    public void WriteMessage(string message)
    {
        Console.WriteLine(string.Concat("SomeRelatedLibraryClass WriteMessage: ", message));
    }
}
+1  A: 

AFAIK, if the class you're trying to mock out isn't virtual or an interface - you can't mock it with Moq. If your 3rd party library doesn't implement their classes, I think you're out of luck.

Mike
+1  A: 

I would suggest using the Gateway pattern. Rather than depend directly on SomeRelatedLibraryClass, create an interface ISomeRelatedLibraryClassGateway. Expose all of SomeRelatedLibraryClass' methods that you need to call with methods of the same signature on ISomeRelatedLibraryClassGateway.

public interface ISomeRelatedLibraryClassGateway {
  void WriteMessage(string message);
}

Then create an implementation that routes all calls to the third party class:

public class SomeRelatedLibraryClassGateway : ISomeRelatedLibraryClassGateway {
  private readonly SomeRelatedLibraryClass srlc;
  public SomeRelatedLibraryClassGateway(SomeRelatedLibraryClass srlc) {
    this.srlc = srlc;
  }

  void ISomeRelatedLibraryClassGateway.WriteMessage(string message) {
    srlc.WriteMessage(message);
  }
}

Now the classes in your app that would depend on SomeRelatedLibraryClass can now depend on ISomeRelatedLibraryClassGateway instead, and this interface is easy to mock. The class SomeRelatedLibraryClassGateway doesn't really need unit tests; all it does is pass calls through. It does need to be tested in a functional test, but you can do functional testing without mocks.

Hope this helps.

Sean Reilly
Actually the problem is I need to mock SomeRelatedLibraryClass which has as a parameter of type SomeLibraryClass. I'm not clear on how the Gateway pattern allows me to more easily mock that class. I in general do use the Gateway pattern when integrating external dependencies but for this example I left out the interface definition and implementation as I don't think it's relevant to the problem.
spoon16
The point is to avoid mocking SomeRelatedLibraryClass. Using the Gateway pattern allows you to avoid mocking SomeRelatedLibraryClass because (most of) your code doesn't directly depend on it. This is an example of refactoring code so that it is easier to test.
Sean Reilly