In my case I would like to load data from a CSV file but I couldn't pass the filename to the "datasource".
After struggling a bit around I come to this two cent solution.
At first I inherited TestCaseSourceAttirbute
/// <summary>
/// FactoryAttribute indicates the source to be used to provide test cases for a test method.
/// </summary>
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class TestCaseCsvAttribute : TestCaseSourceAttribute
{
public TestCaseCsvAttribute(Type mapped, Type config) : base(typeof(TestCsvReader<,>).MakeGenericType(mapped, config), "Data")
{ }
}
then I created the data layer, in my case a CSV reader.
/// <summary>
/// Test data provider
/// </summary>
/// <typeparam name="T">Type to return in enumerable</typeparam>
/// <typeparam name="C">Configuration type that provide Filenames</typeparam>
public sealed class TestCsvReader<T, C>
{
/// <summary>
/// Initializes a new instance of the <see cref="TestCsvReader{T, C}"/> class.
/// </summary>
public TestCsvReader()
{
this.Config = (C)Activator.CreateInstance<C>();
}
/// <summary>
/// Gets or sets the configuration.
/// </summary>
/// <value>
/// The configuration.
/// </value>
private C Config { get; set; }
/// <summary>
/// Gets the filename.
/// </summary>
/// <value>
/// The filename.
/// </value>
/// <exception cref="System.Exception">
/// </exception>
private string Filename
{
get
{
try
{
string result = Convert.ToString(typeof(C).GetProperty(string.Format("{0}Filename", typeof(T).Name)).GetValue(this.Config));
if (!File.Exists(result))
throw new Exception(string.Format("Unable to find file '{0}' specified in property '{1}Filename' in class '{1}'", result, typeof(C).Name));
return result;
}
catch
{
throw new Exception(string.Format("Unable to find property '{0}Filename' in class '{1}'", typeof(T).Name, typeof(C).Name));
}
}
}
/// <summary>
/// Yields values from source
/// </summary>
/// <returns></returns>
public IEnumerable Data()
{
string file = this.Filename;
T[] result = null;
using (StreamReader reader = File.OpenText(file))
{
//TODO: do it here your magic
}
yield return new TestCaseData(result);
}
}
Then I created a class with the only scope to contain properties with the file paths. There's a name convention about the property, that's ClassTypeName + "Filename".
public class Configurations
{
public string ConflictDataFilename
{
get
{
return @"C:\test.csv";
}
}
}
At this point just decorate accordingly the test, with the type of class to map to data and the class that contain file path.
[Test(Description="Try this one")]
[TestCaseCsv(typeof(ClassMappedToData), typeof(Configurations))]
public void Infinite(ClassMappedToData[] data)
{
}
Hope this can help a bit.