Integration Testing FTP Connections in .NET

13 篇文章 0 订阅

When writing testable code, your first port of call is often to abstract any dependencies and make them easy to mock. This is the same for any of your codebase that talks to FTP servers. Testing the way your code behaves under real world conditions makes integration tests important regardless of abstraction, though. Here’s a simple trick to test FTP code in the wild.

imageA recent project of mine has involved writing code that talks to FTP servers with the goal of adding additional continuous integration automation to a project. Although all of my main methods are easily abstracted and injectable, my project still needs to actually talk to FTP servers at the end of the day, and I need to test that these very methods do the right thing when they are met with different conditions; be they bad credentials, lack of read/write permissions etc.

The Challenge

Integration tests can be brittle at the best of times, so ensuring that they are repeatable and can be setup and torn down can often be almost as much of a challenge as writing your actual code itself.

An FTP server is usually a static service that is installed on a server. You might think that running one and ensuring it stays up and doesn’t get hacked just so that all your integration tests work is a necessary evil, but there is an easier way.

Run local. Run often.

I was running an FTP server on my build server just so that it was “always around” for my tests until i stumbled across an interesting project over on GitHub to do just this.

The approach I'm about to show you doesn’t need you to go to the effort of running a dedicated server at all. All you need to do is add a single executable to your unit test project and wrap your unit test in a using statement.

The FTP server executable is a single file FTP server called FTPDMIN which offers a read/write FTP server that can be fired up from the command line with a minimum feature set and only a few command line parameters to make it all tick.

By implementing IDisposable the helper class that wraps around this command line exe allows you to take advantage of the using() pattern to take care of your executable’s lifetime and have it die when your code is done testing.

Steps to make it happen

Download FTPDMIN from here.

Add the exe to the root of your test project (you can put this anywhere, but you’ll have to update the helper class below).

Now add the exe to your project (i.e “view all items” in your test project’s solution explorer, and add the exe).

Set the EXE to “Copy always” in it’s solution properties.

image

Add the following code to a helper class in your Test Project:

public class FtpTestServer: IDisposable
{
    private readonly Process ftpProcess;

    public FtpTestServer(string rootDirectory, int port = 21, bool allowUploads = true)
    {
        var psInfo = new ProcessStartInfo
            {
                FileName = AppDomain.CurrentDomain.BaseDirectory + "\\ftpdmin.exe",
                Arguments = String.Format("-p {0} -ha 127.0.0.1 \"{1}\" {2}", port, rootDirectory, allowUploads ? string.Empty : "-g"),
                WindowStyle = ProcessWindowStyle.Hidden
            };
        ftpProcess = Process.Start(psInfo);
    }

    public void Dispose()
    {
        if (ftpProcess.HasExited) return;
        ftpProcess.Kill();
        ftpProcess.WaitForExit();
    }
}

Now you can enjoy being able to write really clean integration testing code that starts and FTP server every time you run your tests and then tear it down when your test is done.

An example integration test showing connecting to “127.0.0.1”:

[TestMethod]
public void FtpCode_Upload_CanConnect()
{
    try
    {
        // Fire up a new Ftp server instance
        using (new FtpTestServer(rootDirectory: "./"))
        {
            // code that talks to an FTP server on 127.0.0.1
        }
    }
    catch (WebException e)
    {
        Assert.Fail("Failed to connect to our FTP server");
    }
}

How awesome is that?

The power of using FTPDMIN is that it can be told to deny write permissions to simulate bad user permissions as well:

[TestMethod]
public void FtpCode_Upload_ThrowsWebException()
{
    try
    {
        // Fire up a new Ftp server instance
        using (new FtpTestServer(rootDirectory: "./", allowUploads: false))
        {
            // code that talks to an FTP server on 127.0.0.1
        }
    }
    catch (WebException e)
    {
        Assert.Fail("Our code failed to upload a file because of invalid permissions");
    }
}

All in all, the above has been a complete lifesaver when it comes to making my integration test projects portable – if a new developer joins my project, they instantly get access to my FTP test harness just by pulling down my project’s source code.

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值