1

I have a class that uses .NETS SerialPort class to communicate with a device.

I want to use Mocks to help write tests for my class, ideally I would like to create a Mock for the SerialPort class.

I believe I can't create a mock of SerialPort because the class has no vritual methods, is that correct?

To work around this limitation, I have created an interface and an implementation MyComPort. Using this I'm able to implement some test. However, I would like to avoid needing to have the MyComPort class. Is this possible?


IComPort

Interface that I will use to make the Mock.

public interface IComPort{   
    int ReadTimeout { get; set; }   
    void Open();    
    void Write(String data);    
    String ReadExisting();    
    int ReadChar();    
    void DiscardInBuffer();
}

MyComPort

Class that I use to wrap the .NET SerialPort and implement the IComPort interface.

I want to avoid needing this class. If it's not possible, I want to know if it's a good idea to make all the methods AgressiveInlining.

public class MyComPort : SerialPort, IComPort{

    public new int ReadTimeout {
        get { return base.ReadTimeout; }
        set { base.ReadTimeout = value; }
    }

    public MotorComPort(String portName, int baudrate, Parity parity, int databits, StopBits stopbits)
        : base(portName, baudrate, parity, databits, stopbits) { }

    public new void Open() {
        base.Open();
    }

    public new void Write(String data) {
        base.Write(data);
    }

    public new String ReadExisting() {
        return base.ReadExisting();
    }

    public new int ReadChar() {
        return base.ReadChar();
    }

    public new void DiscardInBuffer() {
        base.DiscardInBuffer();
    }
}

ClassThatUsesComPort

The class that uses the serial port, which is the one I want to test.

public class ClassThatUsesComPort{

    private IComPort mComPort;

    public ClassThatUsesComPort(IComPort cP){
        mComPort = cP;
    }

    [...]
}

Main

The main, example of how I'm using the class I want to test.

class Program{
    static void Main(...){
        MyComPort mcp = new MyComPort(...);
        ClassThatUsesComPort x = new ClassThatUsesComPort(mcp);
        [...]
    }
}
forsvarir
  • 10,749
  • 6
  • 46
  • 77
Truman
  • 31
  • 7
  • Why would you need to mock `MyComPort`? Showing sample of unit test could clarify your problem... – Alexei Levenkov Jun 22 '15 at 15:56
  • I assume it's `ClassThatUsesComPort` that you want to test? If so, you are taking the right approach (unless you want to delve into the murky world of mocking frameworks that rewrite assemblies to change the apparent behaviour of existing classes, eg see https://github.com/Fody/Virtuosity) – David Arno Jun 22 '15 at 15:57
  • The alternative is to use something like MSFakes, JustMock or Isolator which can stub out or change methods of pretty much anything – James Jun 22 '15 at 16:00
  • I'm a beginner in the Mock world, I prefere to use the standard Mock API of .NET framework. – Truman Jun 22 '15 at 16:04
  • @JamesBarrass and the free Moq... based on my experience, Moq > Isolator. – Zoomzoom Jun 22 '15 at 16:07
  • It is a good idea to use templates? I mean, `ClassThatUsesComPort` as template with one parameter, this parameter could be SerialPort itself or my Interface. In this case, I can use the Interface and the "bad" class for debug and the SerialPort itself for release, is this a good idea? – Truman Jun 22 '15 at 16:08
  • @Zoomzoom I didn't think Moq supported profiler based call interception? You would still have to provide some kind of adapter class/interface to use Moq? – James Jun 22 '15 at 16:13

1 Answers1

2

You're going down the right approach by creating an isolation point between your application and the serial port so that you can test your classes logic. You're also correct that you can't just use Moq to Mock the SerialPort class. As has been said in the comments, there are some mocking frameworks, like TypeMock that will let you mock the SerialPort directly however they tend to be expensive and because they are so powerful you don't always get the the code structure benefits that you are encouraged to discover if you use a more traditional mocking framework like Moq.

Personally, I would favour aggregating the SerialPort, rather than inheriting from it. I think it makes it more explicit what behaviours from the SerialPort class you're exposing. By inheriting from it, all of the existing behaviour that you've not overridden will be available to your application and there's a higher likelihood that you'll call those methods without first adding them to the interface. So, your class would look more like this:

public class MySerialPort: IComPort, IDisposable {
    SerialPort _serialPort;

    public MotorComPort(String portName, int baudrate, Parity parity, int databits, 
                        StopBits stopbits)
    {
        _serialPort = new SerialPort(portName, baudrate, parity, databits, stopbits);
    }
    // ...
}

As far as "AggressiveInlining" goes, the wrapper code that's going to be produced should be small and might be a candidate for the compiler to inline anyway. However, you should be calling the methods via the interface that you've declared IComPort. Since you're doing it via the interface, the compiler won't inline them (it simply doesn't know that you're always going to be calling the method on a particular concrete class). If the compiler did inline the concrete implementation, then you wouldn't be able to provide a mock of the interface to your class in order to achieve different behaviour.

Community
  • 1
  • 1
forsvarir
  • 10,749
  • 6
  • 46
  • 77
  • Then If I add the SerialPort to the `MyComPort` instead of inherit from it, the compiler will inline the wrapper methods? – Truman Jun 26 '15 at 16:30
  • @Truman It's not quite that straightforward. Have a look at http://stackoverflow.com/q/616779/592182 . Generally speaking, make a reasonable effort to write good code, then revisit if/when you find performance issues. That way you can focus your energy on the bits of your system that need it. Unless you've got some evidence that the wrapper code is causing performance issues, then looking at ways to optimize it is probably wasting time that you could be using to provide some other bit of functionality. – forsvarir Jun 26 '15 at 17:23