Reputation: 668
I have the following problem. I want to test a generic class MyClass<'T>. However, I don't really care about the type being used for T. However, when I create an instance of MyClass in the test, I need to specify what T is supposed to be. I can do it like that:
var sut = new MyClass<Object>();
It works of course, however, I don't like to put Object specifically, because it suggests to someone reading this test that maybe Object type is somehow significant here.
I like the approach used by AutoFixture where each value is created using fixture.Create<T>()
, because it shows the reader that the value is not really important. Example of that:
[Fact]
public void IntroductoryTest()
{
// Arrange
Fixture fixture = new Fixture();
int expectedNumber = fixture.Create<int>();
MyClass sut = fixture.Create<MyClass>();
// Act
int result = sut.Echo(expectedNumber);
// Assert
Assert.Equal(expectedNumber, result);
}
In the code above we don't care about the number, so we use AutoFixture as an abstraction about the fact that some number is needed.
Is there a solution like that, but in regard to types being used with generic classes?
Something like: var sut = MyClass<fixture.GenericType>();
I don't care here what is the actual type. To explain my use-case a bit more: I have AutoFac module that is used to register MyClass. In my test I just want to test if the module registers MyClass properly. For that registration I don't want to specify some exact type to be used for MyClass. It can be any.
Upvotes: 0
Views: 871
Reputation: 734
Currently AutoFixture doesn't support non-closed generic types activation and it's unlikely it will change one day.
Firstly it's caused by the fact that the C# language itself supports non-closed generic types for the reflection purpose only. You cannot declare variable of MyClass<>
type without closing the type over particular T
. Hence, even if AutoFixture substitute type and activate an instance for you, it will be hard to work with the result - you'd either need to use a variable of object
type or rely on covariance if your type supports that. None of those options looks usable.
Secondly, the task itself is very hard as generic type could have constrains. Sometimes constrains could get crazy and e.g. have cyclic dependencies: class MyClass<T1, T2> where T1 : T2 where T2 : IEnumerable<T1>
. The AutoFixture.Idioms
library already tries to solve that problem for the GuardClauseAssertion
, but the success is average. This feature requires dynamic type generation (which BTW is not supported on all the platforms) and very advanced usage of the Reflection.Emit
API, which makes it very hard to implement correctly.
Upvotes: 1
Reputation: 77866
Probably you can define a base type say IBase
, where all your T types implements IBase (Class1<T> where T : IBase
) and then you can say var sut = new MyClass<IBase>();
Upvotes: 1