我有一个读取pop3电子邮件服务器的类。我想为包含类编写一些单元测试,所以我需要模拟POP3服务器类。我正在使用OpenPOP.Net。所以我有一个像这样的构造函数:
EmailHost(string email, string password, string pop3Address, int port)
... etc....
然后我有一个连接类:
private void Connect()
{
_pop3 = new Pop3Client();
etc...
因此,对Pop客户端的引用被埋没在类的内容中。为了能够模拟它,我需要做一些时髦的东西,因为在Pop3Client上使EmailHost成为通用,或者添加一些默认的函数来执行以上行:
public EmailHost<PopClass>(...)
或
public EmailHost(... params, Func popGenerate = () => new Pop3Client())
所以看来我必须稍微妥协一下我的构造函数才能使它与mock一起工作。 (显然我会定义一个IPop3Client等等。)
有关如何正确执行此操作的任何想法?
编辑:
jOk提供了一个有趣的答案,问题是它不适合我正在做的结构。在这种特殊情况下,我需要在Pop客户端中处理多个电子邮件地址,并动态添加。因此,在添加每个电子邮件地址时,您需要创建一个新的Pop3Client。另外,我想隐藏POP3本身的实现,以便用户不需要尽可能多地了解它。
对此有何其他想法?
感谢您输入btw。
答案 0 :(得分:4)
我认为你很接近。
不要传入最终将用于创建Pop3Client实例的所有参数,而应考虑注入Pop3Client的实例。
public EmailHost(IPop3Client client) {
}
通过这样做,您将从创建Pop3Client对象的职责中删除您的EmailHost类。相反,这个职责转移到其他地方,最常见的是转移到IoC容器。
我无法从您发布的代码中看出Pop3Client是否基于接口。如果它很好,你可以在测试中模拟/存根并注入依赖项。如果没有,那么操作它就会涉及更多工作,以便在这种情况下工作。它可以像在类周围编写一个包装器(和相应的接口)一样简单,它暴露了您在EmailHost中使用的方法。然后可以在上面的示例中使用它来代替IPop3Client。
这有意义吗?如果您需要更多指导,请告诉我。
答案 1 :(得分:0)
使用Castle Windsor之类的东西来做服务地点。如果您不想更改构造函数,请在容器上调用Resolve,但这不是正确的方法。将依赖项放在构造函数中很好并且建议。
答案 2 :(得分:-1)
我相信Moles会让你覆盖_pop3私有局部变量而不做任何代码更改:
http://research.microsoft.com/en-us/projects/pex/downloads.aspx