加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – 模拟复杂的第三方库

发布时间:2020-12-15 21:40:26 所属栏目:百科 来源:网络整理
导读:我有一个使用第三方FTP库 http://ftps.codeplex.com/的类,我想模拟它,以便我可以单独测试该类,而不是FTP库.我已经做到了,但对我来说感觉很麻烦.详细地说,该类使用AlexPilotti.FTPS.Client.FTPSClient类的这些方法: public string Connect(string hostname,E
我有一个使用第三方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,ref bool cancel);

public interface IFTPClient<T1,T2> : IDisposable
{
    string Connect(string hostname,System.Net.NetworkCredential credential);
    ulong PutFile(
        string localFileName,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,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,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,"passwd"))
{
    ftpServer.Connect();
}

…但是,关于你抽象FTP库的方式,我认为这是一个很好的方式:)

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读