サードパーティの 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 ライブラリからデリゲートを取得し、そのデリゲートもライブラリから 2 つの異なる型を取得するため、問題が発生する可能性があります。これらの型から切り離すために、ジェネリックを使用することにしました。
モック オブジェクトを作成できるようにするために、インターフェイスを作成してから、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);
}
このような状況での通常のアプローチは何ですか? 私のアプローチは面倒なようで、もっと簡単な方法があるかどうか疑問に思っています。ありがとう。