Skip to main content
Source Link
Ayb4btu
  • 133
  • 1
  • 5

Wrapping a CSV file for access and testing

I have a simple class that represents and accesses the data from a CSV file (using the CsvHelper library). I've tried restructuring the code to allow for better unit testing, but I'm sure the structure of the class could be better; both for testing and for using it (I'm not sure if there is any standard recommendations for these types of classes).

Here is the class code:

public class CsvCountFile
{
    public string AbsolutePath { get; }
    public string Delimiter { get; }

    public LocationDefinition LocationData { get; private set; }
    public List<CountDefinition> CountData { get; private set; }

    public CsvCountFile(string absolutePath, string delimiter = ",")
    {
        AbsolutePath = absolutePath;
        Delimiter = delimiter;
    }

    public void ReadCountData()
    {
        using (var fileReader = File.OpenText(AbsolutePath))
        {
            ReadCountData(fileReader);
        }
    }

    public void ReadCountData(TextReader fileReader)
    {
        CountData = new List<CountDefinition>();

        using (var csvReader = new CsvReader(fileReader))
        {
            csvReader.Configuration.HasHeaderRecord = false;
            csvReader.Configuration.RegisterClassMap<LocationMap>();
            csvReader.Configuration.RegisterClassMap<CountMap>();

            csvReader.Read(); // get header
            csvReader.Read(); // get first record
            LocationData = csvReader.GetRecord<LocationDefinition>();

            csvReader.Read(); // skip blank line
            csvReader.Read(); // skip second header section

            while (csvReader.Read())
            {
                var count = csvReader.GetRecord<CountDefinition>();
                CountData.Add(count);
            }
        }

    }
}

The ReadCountData was split into two so that the reading logic could be tested by forming a TextReader in memory, instead of needing an actual csv file. While this code works, I don't foresee any usage scenarios that would typically require reading the csv by passing in a TextReader.

Also, due to this structure, when CsvCountFile is constructed, the csv absolutePath is passed in, but testing using a TextReader doesn't require this, and it doesn't feel right instantiating it with an empty string.