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,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库的方式,我认为这是一个很好的方式:) (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |