Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit tests: where to stop?

The classical solution if you have a concrete implementation of a dependency in a class you want to test is: add a layer of indirection where you have full control.

So it comes to adding more and more of indirection layers (interfaces that can be stubs/mocks in unit tests).

But: somewhere in my tests I must have the "real" implementation of my dependency. So what about this? Test? Don't test?

Take this example:

I had some dependencies on paths that I need in my application. So I extracted an interface, IPathProvider (that I can fake in my tests). Here is the implementation:

public interface IPathProvider
{
    string AppInstallationFolder { get; }
    string SystemCommonApplicationDataFolder { get; }
}

The concrete implementation PathProvider looks like this:

public class PathProvider : IPathProvider
{
    private string _appInstallationFolder;
    private string _systemCommonApplicationDataFolder;

    public string AppInstallationFolder
    {
        get
        {
            if (_appInstallationFolder == null)
            {
                try
                {
                    _appInstallationFolder =
                        Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
                }
                catch (Exception ex)
                {
                    throw new MyException("Error reading Application-Installation-Path.", ex);
                }
            }
            return _appInstallationFolder;
        }
    }

    public string SystemCommonApplicationDataFolder
    {
        get
        {
            if (_systemCommonApplicationDataFolder == null)
            {
                try
                {
                    _systemCommonApplicationDataFolder =
                        Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData);
                }
                catch (Exception ex)
                {
                    throw new MyException("Error reading System Common Application Data Path.", ex);
                }
            }
            return _systemCommonApplicationDataFolder;
        }
    }
}

Do you test such code and if, how?

like image 982
joerg Avatar asked Oct 14 '25 03:10

joerg


1 Answers

That PathProvider class seems a lot like a database repository class - it integrates with an external system (e.g., filesystem, database, etc).

These classes live at the boundaries of your system - other classes depend on them, and they depend solely on an external system. They connect your system to the external world.

As such, they're subject to integration testing - not unit testing.

I usually just tag my tests (e.g. with xUnit's Trait attribute) to keep them separate from regular tests, and so I can disable them when running in isolation (e.g. without a database). An alternative would be to separate them into a whole new project in the same solution, but I personally think that's overkill.

[Fact, Trait("Category", "Integration")]
public void ReturnsCorrectAppInstallationFolder()
{
    // Arrange
    var assemblyFilename = Path.GetFilename(typeof(SomeType).Assembly.Location);
    var provider = new PathProvider();

    // Act
    var location = provider.AppInstallationFolder;

    // Assert
    Assert.NotEmpty(Directory.GetFiles(location, assemblyFilename))
}
like image 121
dcastro Avatar answered Oct 17 '25 07:10

dcastro



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!