You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Connected.Common.Types/Common.Types.Tests/InstanceFaker.cs

62 lines
1.4 KiB

2 years ago
using Moq;
namespace Common.Types;
internal class InstanceFaker<T>
{
private readonly Dictionary<Type, Mock> _mocks = new();
private bool _mocksGenerated = false;
public InstanceFaker()
{
if (typeof(T).GetConstructors().Length > 1)
throw new Exception($"Multiple constructors for type {typeof(T).FullName} found. Auto resolve not possible.");
GenerateMocks();
}
private void GenerateMocks()
{
if (_mocksGenerated)
return;
_mocksGenerated = true;
var constructor = typeof(T).GetConstructors()[0];
var parameters = constructor.GetParameters();
foreach (var parameter in parameters)
{
if (!parameter.ParameterType.IsInterface)
throw new Exception($"Constructor parameter {parameter.Name} of type {parameter.ParameterType.FullName} is not an interface, cannot mock.");
_mocks.Add(parameter.ParameterType, CreateMock(parameter.ParameterType));
}
}
private T ProcessType()
{
GenerateMocks();
var constructor = typeof(T).GetConstructors()[0];
var mocks = _mocks.Select(e => e.Value.Object);
return (T)constructor.Invoke(mocks.Cast<object>().ToArray());
}
private Mock? CreateMock(Type type)
{
var creator = typeof(Mock<>).MakeGenericType(type);
return Activator.CreateInstance(creator) as Mock;
}
public Mock<T>? GetMock<T>()
where T : class => _mocks.GetValueOrDefault(typeof(T)) as Mock<T>;
private T _instance;
public T Instance => _instance ??= ProcessType();
}