我有一个实体和一个验证器:
public class Customer : IEntity { /* ... */ }
public class CustomerValidator : IValidator<Customer> { /* ... */ }
我想模仿验证工厂:
public interface IValidatorFactory
{
IValidator<TEntity> create<TEntity>(TEntity entity) where TEntity : class, IEntity;
}
我的模拟:
var mockFactory = Substitute.For<IValidatorFactory>();
mockFactory.create(Arg.Any<Customer>()).Returns(m => new CustomerValidator());
当参数为Customer
时,此方法有效。
但我正在测试的代码传递IEntity
,因此模拟不起作用。
我可以重写mock来处理输入到接口的参数而不是具体的类吗?
答案 0 :(得分:2)
您正在处理泛型,默认情况下它们不“保留”类型参数继承。默认情况下,通用类型参数是不变的。这意味着您无法将IValidator<Customer>
的实例作为IValidator<IEntity>
返回,即使Customer
来自IEntity
。您需要明确指定逆变关系,使您能够使用比最初实例化的IValidator<IEntity>
更通用的类型IValidator<Customer>
。只需使用out
关键字标记type参数:
public interface IValidator<out T> where T : IEntity { }
您可以在"Covariance and Contravariance in Generics"
中阅读以下是完整的示例:
public interface IValidatorFactory
{
IValidator<TEntity> create<TEntity>(TEntity entity) where TEntity : class, IEntity;
}
public interface IEntity { }
public interface IValidator<out T> { }
public class Customer : IEntity { }
public class CustomerValidator : IValidator<Customer> { }
[Test]
public void SO_43360005()
{
var sub = Substitute.For<IValidatorFactory>();
sub.create(Arg.Is<IEntity>(x => x is Customer)).Returns(_ => new CustomerValidator());
}