Unit Testing Methods With File IO

谁说我不能喝 提交于 2019-12-03 07:21:11

Regarding how to test File I/O: A common way of doing this is encapsulating File I/O in a wrapper class. For example:

public class FileHandler : IFileHandler
{
     public string GetFilename(string name)
     {
         return System.IO.GetFileName(name);
     }

    public string GetDirectoryName(string directory)
    {
         return System.IO.GetDirectoryName(directory);
    }
}

public interface IFileHandler
{
      string GetFilename(string name);
      string GetDirectoryName(string directory);
}

In your method under test, you only program against the interface. When you run your unit test, you would use a mock object which returns predefined values. For this, you could use Moq.

This is a bit work to do but then you do not need to test File I/O as well.

Best Jan

How can i test a method using IO?

By introducing abstraction over the .NET's IO libraries and then using real implementation (BCL) in application, and fake (mocked) one in unit test. Such abstraction is fairly simple to write on your own, but those projects already exist (eg. System.IO.Abstraction) so reinventing wheel is pointless, especialy in such trivial matter.

I don't really want to be using a real file as this would be slow

This is correct, in test you want to use fake (mock) objects.

Is a project like this worth unit testing?

Every project is worth testing and you will test it in one way or another (in most extreme case, by manually executing application and doing good, old click-and-wait testing).

Note that almost always it is too time consuming to manually test 10 edge cases of complex parser method which everytime requires you to load large file and wait for results. This is where automated tests in isolated environment help greatly. It is the same with your code - file system, web service, they all introduce large overhead before you can get to actual business logic. Must isolate.

A lot of the methods in this project are private (...) I've read you should only really test methods which are externally visible

Correct again, you should be testing public contract. However, if private stuff gets big enough to test it, most of the times it's a good indicator it is also big enough to put it in its own class. Note that changing members access modifiers only for the unit test usage is not the best idea. Almost always it's better to extract-class/method refactor.

kirillta

I'm pretty new with TDD too, but I think I can get some suggestion to you:

  1. About IO testing. You can use mock objects. Create a mock for the method you want to test and compare it with real passed in value. In Moq Framework it looks like that:

    var mock = new Mock<IRepository<PersonalCabinetAccount>>();
    mock.Setup(m => m.RemoveByID(expectedID))
        .Callback((Int32 a) => Assert.AreEqual(expectedID, a));
    
    var account = new PersonalCabinetAccount {ID = myID};
    var repository = mock.Object;
    repository.RemoveByID(account.myId);
    
  2. Absolutely, yes. If you want to get a habit, you need to test everything, i suppose. That way knowledge comes ;)

  3. You can use InternalsVisibleTo attribute to avoid visibility issues.

    test methods which are externally visible

I think this one about enterprise programming. just a spare of time with your own trusted code.

Hope my point can help you.

You can do that using Microsoft Fakes. First generate a fake assembly for System.dll - or any other package and then mock expected returns as in:

using Microsoft.QualityTools.Testing.Fakes;
...
using (ShimsContext.Create())
{
     System.IO.Fakes.ShimDirectory.ExistsString = (p) => true;
     System.IO.Fakes.ShimFile.MoveStringString = (p,n) => {};
     // .. and other methods you'd like to test

     var result = RestoreExtension("C:\myfile.ext");
     // then you can assert with this result 
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!