C# – How to Unit Test Code that Downloads a File from GitHub

cgithubmockingunit testing

This is my solution's structure:

Storage.csproj
   > FileDownloader.cs
   > GitHubProvider.cs (implements IStorageProvider)
   > IStorageProvider.cs

Storage.Test.csproj
   > FileDownloaderFixture.cs

The idea is that I can use the class FileDownloader, inject it with a IStorageProvider, call myFileDownloader.Download(url), and it will download the file to the filesystem.

Now, the question is: how do I unit test this? I wrote the following test:

[TestClass]
    public class FileDownloaderFixture
    {
        [TestMethod]
        public void TestDownload()
        {
            //Arrange
            var storageProviderMock = new Mock<IStorageProvider>(MockBehavior.Strict);
            storageProviderMock.Setup(s => s.Download("http://host.com/file.txt")).Returns(Status.Success);
            var myFileDownloader = new FileDownloader(storageProviderMock.Object);

            //Act
            myFileDownloader.DownloadFile("http://host.com/file.txt");

            //Assert
            storageProviderMock.Verify(s => s.Download("http://host.com/file.txt"));
        }
    }

It looks nice and clean, but… it's useless. It doesn't prove the fact that the code in GitHubProvider.Download(url) works. I don't even use methods from GitHubProvider. So what's the point?

The only other idea I have is to set up a test GitHub account & repository, and work with that. But this solution won't work very well if, for instance, I had to pay for each access to the repository. What then?

Best Answer

The file downloader has two external dependencies: a connection to Git is where data comes in. A connection to the file system is where data goes out.

To be a unit test, your test should abstract from both these collaborators - you don't want to test the Git network protocol, and you don't want to test file system code either. That leaves the behaviour of your class simple and easily testable: it issues commands to the Git hub to obtain data and issues commands to the storage system to write them. That makes for a pretty primitive test, and this is good. A class should do one thing, and do it well. ideally, it should be so simple that it is obviously correct (and have a unit test as well, for cases when the obviousness is misleading).

You're right that this doesn't prove that your system successfully downloads stuff. That is the task of an integration, acceptance, or load test, and you need those as well, but as far as unit testing goes, there is nothing wrong with tests that seem almost trivial. Your project will grow in complexity soon enough, and without a safety net composed of almost trivial checks, you can't manage that growth responsibly.