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.