c# – 模拟复杂的第三方库
作者:互联网
我有一个使用第三方FTP库http://ftps.codeplex.com/的类,我想模拟它,以便我可以单独测试该类,而不是FTP库.我已经做到了,但对我来说感觉很麻烦.详细地说,该类使用AlexPilotti.FTPS.Client.FTPSClient类的这些方法:
public string Connect(string hostname, ESSLSupportMode sslSupportMode)
public ulong PutFile(
string localFileName, string remoteFileName,
FileTransferCallback transferCallback)
委托AlexPilotti.FTPS.Client.FileTransferCallback如下所示:
public delegate void FileTransferCallback(
FTPSClient sender, ETransferActions action,
string localObjectName, string remoteObjectName,
ulong fileTransmittedBytes, ulong? fileTransferSize, ref bool cancel);
您可以看到问题,因为PutFile从FTP库获取委托,该委托也从库中获取两种不同的类型.我决定使用泛型来解耦这些类型.
为了能够创建一个模拟对象,我创建了一个接口,然后创建了一个派生类,它是FTP库功能的包装器.
// Interface so that dependency injection can be used.
public delegate void FileTransferCallback<T1, T2>(T1 sender, T2 action,
string localObjectName, string remoteObjectName,
ulong fileTransmittedBytes, ulong? fileTransferSize,
ref bool cancel);
public interface IFTPClient<T1, T2> : IDisposable
{
string Connect(string hostname, System.Net.NetworkCredential credential);
ulong PutFile(
string localFileName, string remoteFileName,
FileTransferCallback<T1, T2> transferCallback);
}
// Derived class, the wrapper
using FTPSClient = FTPS.Client.FTPSClient;
using ETransferActions = FTPS.Client.ETransferActions;
public class FTPClient : IFTPClient<FTPSClient, ETransferActions>
{
public FTPClient()
{
client = new AlexPilotti.FTPS.Client.FTPSClient();
}
public ulong PutFile(
string localFileName, string remoteFileName,
FileTransferCallback<FTPSClient, ETransferActions> transferCallback)
{
callback = transferCallback;
return client.PutFile(localFileName, remoteFileName, TransferCallback);
}
public void Dispose()
{
client.Dispose();
}
public string Connect(
string hostname, System.Net.NetworkCredential credential)
{
return client.Connect(hostname, credential,
FTPS.Client.ESSLSupportMode.ClearText);
}
void TransferCallback(
FTPS.Client.FTPSClient sender, FTPS.Client.ETransferActions action,
string localObjectName, string remoteObjectName,
ulong fileTransmittedBytes, ulong? fileTransferSize,
ref bool cancel)
{
callback.Invoke(sender, action, localObjectName, remoteObjectName,
fileTransmittedBytes, fileTransferSize, ref cancel);
}
private AlexPilotti.FTPS.Client.FTPSClient client;
private FileTransferCallback<FTPSClient, ETransferActions> callback;
}
这是一个使用此接口的类,我进行单元测试.我把它剥了一下,所以只使用了Connect方法,但我希望它仍然能说明我的问题.
public class FTPServerConnection<T1, T2>
{
public void Init(
IFTPClient<T1, T2> client, string serverName,
string userName, string passwd)
{
IsConnected = false;
ServerName = serverName;
UserName = userName;
Passwd = passwd;
ftpClient = client;
Connect();
}
public void Connect()
{
ftpClient.Connect(
ServerName,
new System.Net.NetworkCredential(UserName, Passwd));
}
public string ServerName { protected set; get; }
public string UserName { protected set; get; }
public string Passwd { protected set; get; }
public bool IsConnected { protected set; get; }
private IFTPClient<T1, T2> ftpClient;
}
最后单元测试:
[TestMethod()]
public void FTPServerConnectionConstructorTest()
{
var ftpClient = new Mock<IFTPClient<object, object>>();
var ftpServer = new FTPServerConnection<object, object>();
ftpServer.Init(ftpClient.Object, "1.2.3.4", "user", "passwd");
Assert.AreEqual("1.2.3.4", ftpServer.ServerName);
Assert.AreEqual("user", ftpServer.UserName);
Assert.AreEqual("passwd", ftpServer.Passwd);
}
在像这样的情况下,通常的做法是什么?我的方法似乎很混乱,我想知道是否有更简单的方法.谢谢.
解决方法:
我认为这只会感觉很乱,因为你已经让第三方代表应对了,但对我来说它看起来像一个非常标准的抽象/模拟方法.
我唯一的评论是FTPServerConnection的结构看起来有点不标准;它的编写方式你必须在无效状态下实例化一个(即一个没有客户端细节的状态)然后调用Init(),它本身调用Connect()(从测试的外观来看,它从不被服务器的客户端调用)类).我会说在FTPServerConnection构造函数中提供Init()的参数更为正常,然后完全删除Init()方法并让客户端执行此操作:
var ftpClient = new Mock<IFTPClient<object, object>>();
using (var ftpServer = new FTPServerConnection<object, object>(
ftpClient.Object,
"1.2.3.4",
"user",
"passwd"))
{
ftpServer.Connect();
}
…但是,关于你抽象FTP库的方式,我认为这是一个很好的方式:)
标签:c,unit-testing,mstest,moq 来源: https://codeday.me/bug/20190709/1413648.html