How do people approach mocking out TcpClient (or things like TcpClient)?
I have a service that takes in a TcpClient. Should I wrap that in something else more mockable? How should I approach this?
When coming to mock classes that are not test friendly (i.e. sealed/not implementing any interface/methods are not virtual), you would probably want to use the Adapter design pattern.
In this pattern you add a wrapping class that implements an interface. You should then mock the interface, and make sure all your code uses that interface instead of the unfriendly concrete class. It would look something like this:
public interface ITcpClient
{
Stream GetStream();
// Anything you need here
}
public class TcpClientAdapter: ITcpClient
{
private TcpClient wrappedClient;
public TcpClientAdapter(TcpClient client)
{
wrappedClient = client;
}
public Stream GetStream()
{
return wrappedClient.GetStream();
}
}
I think @Hitchhiker is on the right track, but I also like to think about abstracting out things like that just a step further.
I wouldn't mock out the TcpClient directly, because that would still tie you too closely to the underlying implementation even though you've written tests. That is, your implementation is tied to a TcpClient method specifically. Personally, I would try something like this:
[Test]
public void TestInput(){
NetworkInputSource mockInput = mocks.CreateMock<NetworkInputSource>();
Consumer c = new Consumer(mockInput);
c.ReadAll();
// c.Read();
// c.ReadLine();
}
public class TcpClientAdapter : NetworkInputSource
{
private TcpClient _client;
public string ReadAll()
{
return new StreamReader(_tcpClient.GetStream()).ReadToEnd();
}
public string Read() { ... }
public string ReadLine() { ... }
}
public interface NetworkInputSource
{
public string ReadAll();
public string Read();
public string ReadLine();
}
This implementation will decouple you from Tcp related details altogether (if that is a design goal), and you can even pipe in test input from a hard coded set of values, or a test input file. Very hand if you are on the road to testing your code for the long haul.
Using the Adapter pattern is most definitely the standard TDD approach to the problem. You could, however, also just create the other end of the TCP connection and have your test harness drive that.
IMO the widespread use of adapter class obfuscates the most important parts of a design, and also tends to remove a lot of stuff from being tested that really ought to be tested in context. So the alternative is to build up your testing scaffolding to include more of the system under test. If you are building your tests from the ground up, you'll still achieve the ability to isolate the cause of a failure to a given class or function, it just won't be in isolation...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With