Struggling with Moq - Using Moqs within the method under test

Viewed 79

In my system, I have a singleton class that is responsible for listing and delisting a selection of USB devices. This class is "InterfaceHandler".
Now, I am trying to test this class and presumably need to use Mocking (in this case Moq).
Amongst other things, the InterfaceHandler has to instantiate whichever hardware interface that gets detected. This is done within a method called "CreateCommunicationInterface()" as here below:

public class InterfaceHandler {
   public IHardware Hardware { get; set; }

   private InterfaceHandler() {}

   private static InterfaceHandler _instance;
   public static InterfaceHandler Instance() => (_instance) ?? (_instance = new InterfaceHandler());

   public IHardware CreateCommunicationInterface(HardwareType detectedHardwareType) {
       try {
           lock (locker) {
               // Create and initialise hardware interface
               switch (detectedHardwareType) {
                case "Harware0":
                    Hardware = new HW0();
                    break;
                case "Harware1":
                    Hardware = new HW1();
                    break;
                case "SimHarware":
                    Hardware = new Simulator();
                    break;
                default:
                    throw new Exception("Unknown Hardware Interface");
               }
            
               // Do something with this Hardware
            }
        } catch (Exception ex) {
            string errorMessage = LogUtils.ComposeErrorMessage(ex, $"Could not create communication interface.");
            Logger.Error(errorMessage);
        }

        return Hardware;
    }
}

The problem I am having here is that if I were to create a unit test and create a Moq for each of the interfaces (HW0, HW1, and Simulator), there would be no way for CreateCommunicationInterface() to use these Moq'ed objects (for the testing of CreateCommunicationInterface()).
I see that in many cases, people inject an Interface at construction, but in this case, we do not know what needs to be instantiated at construction, so I am not sure what is the approach to follow.
Any guidance would be very much appreciated.

1 Answers

The question you should ask here, is what to test.

Let's define the unit: Your unit, would be the construction of the proper object.

The object itself would be tested in another unit testing class specifically made for this. So you would have

  1. An HW0 test class
  2. An HW1 test class
  3. etc.

So in your unit test, depending on the input, you check if the returned instance is of the proper type and you are done with it.

Now if you want to test the consumers you need to mock the InterfaceHandler

To do this you need to declare a new interface IInterfaceHandler with the CreateCommunicationInterface function as a member and have the InterfaceHandler implement it. Then you can control the flow, regardless of your singleton implementation.

Another point. Do you really need the following line?

   public IHardware Hardware { get; set; }

Since it's a singleton, then if multiple threads use it and possibly for different hardware, you might run into weird results, assigning always the latest interface to the member variable.

Related