TDD and Mocking out TcpClient

回眸只為那壹抹淺笑 提交于 2019-12-17 22:52:43

问题


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?


回答1:


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();
   }
}



回答2:


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.




回答3:


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...



来源:https://stackoverflow.com/questions/150341/tdd-and-mocking-out-tcpclient

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!