I have been working on converting my tightly coupled method into one that can be unit tested and have sought some advice on here. I now have my method passing its unit test thanks to some advice - however I now find that I cant call the method from my application. I used to access my GetAllProductsFromCSV() method from the controller with the following:
public ActionResult Index()
{
var products = new ProductsCSV();
List<ProductItem> allProducts = products.GetAllProductsFromCSV();
foreach (var product in allProducts)
{
if (string.IsNullOrEmpty(product.ImagePath))
{
product.ImagePath = "blank.jpg";
}
}
return View(allProducts);
}
The Method was as follows:
public class ProductsCSV
{
public List<ProductItem> GetAllProductsFromCSV()
{
var productFilePath = HttpContext.Current.Server.MapPath(@"~/CSV/products.csv");
String[] csvData = File.ReadAllLines(productFilePath);
List<ProductItem> result = new List<ProductItem>();
foreach (string csvrow in csvData)
{
var fields = csvrow.Split(',');
ProductItem prod = new ProductItem()
{
ID = Convert.ToInt32(fields[0]),
Description = fields[1],
Item = fields[2][0],
Price = Convert.ToDecimal(fields[3]),
ImagePath = fields[4],
Barcode = fields[5]
};
result.Add(prod);
}
return result;
}
}
I have now made the following changes in the ProductCSV class:
public class ProductsCSV
{
private readonly IProductsCsvReader reader;
public ProductsCSV(IProductsCsvReader reader = null)
{
this.reader = reader;
}
public List<ProductItem> GetAllProductsFromCSV()
{
var productFilePath = @"~/CSV/products.csv";
var csvData = reader.ReadAllLines(productFilePath);
var result = parseProducts(csvData);
return result;
}
private List<ProductItem> parseProducts(String[] csvData)
{
List<ProductItem> result = new List<ProductItem>();
foreach (string csvrow in csvData)
{
var fields = csvrow.Split(',');
ProductItem prod = new ProductItem()
{
ID = Convert.ToInt32(fields[0]),
Description = fields[1],
Item = fields[2][0],
Price = Convert.ToDecimal(fields[3]),
ImagePath = fields[4],
Barcode = fields[5]
};
result.Add(prod);
}
return result;
}
Along with the following class & Interface:
public class DefaultProductsCsvReader : IProductsCsvReader
{
public string[] ReadAllLines(string virtualPath)
{
var productFilePath = HostingEnvironment.MapPath(virtualPath);
String[] csvData = File.ReadAllLines(productFilePath);
return csvData;
}
}
public interface IProductsCsvReader
{
string[] ReadAllLines(string virtualPath);
}
As I said, the Unit-Test on method GetAllProductsFromCSV completes successfully now however when I try accessing the method from my controller I get a NullReferenceException on the reader.ReadAllLines call within GetAllProductsFromCSV. It makes sense to me that when I attempt to create an instance of ProductsCSV from within the controller - I am not passing in any parameters... The constructor for the class however requests a IProductsCsvReader. What I cant figure out is how do I actually make the call to the method now? I hope that is clear??