人们如何处理模拟 TcpClient(或类似TcpClient的东西)?
我有一个接收TcpClient的服务。我应该将其包装在更易于模拟的其他东西中吗?我应该怎样处理这个问题?
人们如何处理模拟 TcpClient(或类似TcpClient的东西)?
我有一个接收TcpClient的服务。我应该将其包装在更易于模拟的其他东西中吗?我应该怎样处理这个问题?
当涉及到不太适合测试的模拟类(即封闭的/未实现任何接口/方法不是虚方法),您可能希望使用适配器设计模式。
在这种模式中,您添加一个实现接口的包装类。然后,您应该模拟接口,并确保所有代码都使用该接口而不是不友好的具体类。它看起来会像这样:
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();
}
}
我认为@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相关细节,而且你甚至可以从一个硬编码的值集合或测试输入文件中输入测试数据。如果你正在进行长期代码测试,这非常有用。