Reputation: 5921
I have a external library used to exchange messages.
In this library I have an Object named Channel
.
This is the result after decompiling the dll:
public class Channel
{
public State CurrentState { get { /*Only for code compiling, the value depend on the TCP Connection state.*/return State.ERROR; } }
public bool Send(string message)
{
//Some stuff with TCP connection.
return true;
}
public enum State
{
DISCONNECTED,
CONNECTED,
ERROR
}
}
Now in my code I use this Channel
in a class for sending messages, the class looks like this :
public class ClientConnection
{
private Channel MyChannel;
public ClientConnection(Channel channel)
{
MyChannel = channel;
}
public bool Send(string message)
{
bool result = false;
if(MyChannel.CurrentState == Channel.State.CONNECTED)
{
result = MyChannel.Send(message);
}
return result;
}
}
So my goal is to test it, verifying that the method send is called, and checking that the arguments matches my input. The problem here is that there is no interface and the method are not virtual, so mocking is not possible directly.
What did I do I created a wrapper with overridable Property and Method like this :
public class ChannelWrapper
{
private readonly Channel channel;
public ChannelWrapper(Channel channel)
{
this.channel = channel;
}
public virtual Channel.State CurrentState { get { return channel.CurrentState; } }
public virtual bool Send(string message)
{
return channel.Send(message);
}
}
And changed in ClientConnection
the type Channel
to ChannelWrapper
in the constructor and the property.
The Question
I fell that I should have created an extra interface that matches both Channel
and ChannelWrapper
, and mock using interface instead of overridable members.
And at the same time I really don't see the point of adding a new interface for nothing.
Is there any reason to prefer mocking an interface rather than a class with overridable members? (I am thinking in term of performance mainly too).
Upvotes: 4
Views: 188
Reputation: 5930
The main reason you normally want to mock an interface rather than a concrete type is that, in the case of the concrete type, your mock will have bits and pieces of the actual implementation, potentially leading to unpredictable / undesired behaviour.
For example, the Send method on the Channel currently has "//Some stuff with TCP connection." inside it. What if the Channel class instantiates some web connections and stores them as fields? That means that your mock object now contains actual web connections, even though they might never be used. This might be more serious if we're talking database connections etc.
It may be that this isn't the case in your particular example, but you should think more that you've 'gotten away with it' this time, rather than that being the rule. These concerns mean it's normally much cleaner to mock an interface; you know that your mock object doesn't contain anything that you didn't put there in your test.
I would also see this very similar question: Mocking classes that aren't interfaces
Upvotes: 4