Reputation: 21
I have existing test code which needs to be extended.
I would like to keep this as generic as possible in order to reduce code duplication, here is a simplified snippet of the current code:
public class FilterValueOne { }
[TestClass]
public class TestClass
{
[TestMethod]
public void FilterValueOne_TestMethod()
{
ManipulateData(BuildFilter());
}
private void ManipulateData(FilterValueOne filter)
{
// Do some stuff with filter
}
private FilterValueOne BuildFilter()
{
var filter = new FilterValueOne();
// Initialize filter data members here...
return filter;
}
}
This works, but it is limited to the "FilterValueOne" type.
I want to expand this and make it more generic by implementing a generic type argument.
The code snippet below is what I am after:
// Enum will expand as the app grows
public enum TypeEnum
{
ValueOne,
ValueTwo,
ValueThree
}
// More classes will be added as the app grows
public class FilterValueOne { }
public class FilterValueTwo { }
public class FilterValueThree { }
[TestClass]
public class TestClassGeneric
{
// _filter to be used as the generic type argument
private object _filter;
// Constructor
public TestClassGeneric(TypeEnum val)
{
switch (val)
{
case TypeEnum.ValueOne:
_filter = GetTestObject<FilterValueOne>();
break;
case TypeEnum.ValueTwo:
_filter = GetTestObject<FilterValueTwo>();
break;
case TypeEnum.ValueThree:
_filter = GetTestObject<FilterValueThree>();
break;
default:
_filter = null;
break;
}
}
private T GetTestObject<T>()
where T : class
{
// Code simplified
object returnValue = new object();
return (T)returnValue;
}
[TestMethod]
public void Generic_FilterValue_TestMethod()
{
// Error: The type _filter could not be found. (However it exists)
ManipulateData(BuildFilter<_filter>());
}
private void ManipulateData<T>(T filter)
{
// Do some stuff with filter
}
private T BuildFilter<T>()
where T : class
{
// I want filter to be dynamically assigned to whatever _filter was
// assigned to in the constructor (FilterValueOne/Two/Three), instead
// of "FilterValueOne"
var filter = typeof(T);
// Initialize filter data members here...
return filter;
}
}
I ultimately want to use "_filter" as a generic type argument in my test method, but I can't get it to work. I receive an error stating that "_filter could not be found".
I have tried multiple ways of using typeof(_filter) etc. but no success.
I don't understand generics and its potential fully, I don't know if this is even possible or if I'm simply missing something.
Upvotes: 0
Views: 564
Reputation: 21739
The T
in BuildFilter<T>
is a type parameter. You are passing an instance of a type, in your case an instance of object
(aka System.Object
) not a type.
You simply cannot do that, hence the compiler error (_filter
is not a type; it's an instance and that's why the compiler can't find that "type").
What you want to do instead is instantiate a specific BuildFilter<FilterValueOne>
, etc. and create tests that test each of these things.
For example
[TestMethod]
public void Generic_FilterValueOne_TestMethod()
{
ManipulateData(new BuildFilter<FilterValueOne>());
}
It looks like you're using MS Test; AFAIK MS Test does not support generic tests, so you will have to create a test for each type you're interested in.
Upvotes: 2
Reputation: 5083
It's easier to use generic test class, but if you prefer to pass filter type through contructor or as a method parameter you can use Activator
class.
public class TestClassGeneric<T> where T : new()
{
public void Generic_FilterValue_TestMethod()
{
var filter = new T();
// ManipulateData(filter);
}
}
public class TestClassConstructorArg
{
private readonly Type type;
public TestClassConstructorArg(Type type)
{
this.type = type;
}
public void Generic_FilterValue_TestMethod()
{
var filter = Activator.CreateInstance(type);
// var filter = Activator.CreateInstance(type, BindingFlags.CreateInstance, arguments...);
// ManipulateData(filter);
}
}
Upvotes: 0