10

人们如何模拟 TcpClient(或 TcpClient 之类的东西)?

我有一个接受 TcpClient 的服务。我应该用其他更可笑的东西来包装它吗?我应该如何处理这个?

4

3 回答 3

26

当遇到对测试不友好的模拟类(即密封/未实现任何接口/方法不是虚拟的)时,您可能希望使用适配器设计模式。

在此模式中,您添加一个实现接口的包装类。然后,您应该模拟该接口,并确保您的所有代码都使用该接口而不是不友好的具体类。它看起来像这样:

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();
   }
}
于 2008-09-29T20:23:38.720 回答
5

我认为@Hitchhiker 是在正确的轨道上,但我也想考虑进一步抽象出类似的东西。

我不会直接模拟 TcpClient,因为即使您已经编写了测试,这仍然会使您与底层实现过于紧密地联系在一起。也就是说,您的实现专门与 TcpClient 方法相关联。就个人而言,我会尝试这样的事情:

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

这个实现将把你与 Tcp 相关的细节完全分离(如果这是一个设计目标),你甚至可以从一组硬编码的值或测试输入文件中输入测试输入。如果您正在长期测试您的代码,这将非常有用。

于 2008-09-29T20:50:52.240 回答
2

使用适配器模式绝对是解决问题的标准 TDD 方法。但是,您也可以只创建 TCP 连接的另一端并让您的测试工具驱动它。

IMO 适配器类的广泛使用混淆了设计中最重要的部分,并且还倾向于从测试中删除许多真正应该在上下文中测试的东西。因此,另一种选择是建立您的测试脚手架以包含更多被测系统。如果您从头开始构建测试,您仍然可以获得将失败原因隔离到给定类或函数的能力,它只是不会被隔离......

于 2008-09-29T20:46:12.003 回答