所以我有一个类(库的一部分),便于双向TCP通信。部分原因是接受传入连接。
我的实现包括使用TCPListener对象和多线程方法来接受连接。为了使其可测试,我决定创建一个" INetworkListener" interface,只包含一个事件," OnClientAccepted"。这样,我可以使用依赖注入来模拟伪造版本的TCPListener并避免多线程单元测试。
问题是我需要一种方法来使用假的INetworkListener测试该类,但我希望我的用户不可以选择使用此接口的其他实现。
以下是一些精简的示例代码:
class TcpMessenger
{
// Various properties
private INetworkListener _tcpListener;
public TcpMessenger(int port, string friendlyName) // This is the ONLY constructor I want available to users
{
ServerPort = port;
FriendlyName = friendlyName;
_isRunning = false;
_tcpListener = new ConcreteExample(port); // This prevents unit testing because it opens threads and such
}
public TcpMessenger(int port, string friendlyName, INetworkListener listener) // I need this to test
{
ServerPort = port;
FriendlyName = friendlyName;
_isRunning = false;
_tcpListener = listener; // No dependency here :)
}
}
为什么我不能离开两个构造函数?
我的图书馆就像一个门面。它使TCP通信更容易,但没有增加太多功能。因此,我的目标受众永远不需要注入这种依赖。如果我不想让他们这样做,那么正确的设计会告诉我强制执行它。
为什么不将其作为面向公众的API进行测试?集成测试!
我实际上是用我的库的先前版本做的,这是非常耦合的。结果太可怕了。我有十几个涉及多个线程的测试,更糟糕的是,实际的套接字。单元测试不应该依赖于这样的外部因素。
你真的需要测试吗?
是。此库具有高级功能,例如异常处理,错误报告,连接问题的故障以及维护双向连接的算法(意味着每个节点都是客户端和服务器)。可以在不打开实际套接字的情况下测试此功能,所以我绝对需要它。
我也希望单元测试公开。这意味着任何人都可以获取源,运行它们,并查看所有绿色复选标记。
结束语:
如何独立测试两个类,同时在真实场景中强制依赖?
答案 0 :(得分:2)
您可以使用InternalsVisibleTo
将构造函数设置为内部并将内部公开给测试:
[assembly: InternalsVisibleTo("YourNamespace.YourTests")]