[英]Mocking generic return type in generic method with a expression
我有以下带有通用方法的接口。
public interface IRepository {
Task<TResult> GetByIdAsync<TResult>(
int id,
Expression<Func<Entity, TResult>> expression,
TResult defaultValue = default);
}
在代码表达式的某些部分返回元组和匿名类型。
例子
var _repository = ServiceProvider.GetRequiredService<IRepository>();
var data = await _repository.GetByIdAsync(id, pr => Tuple.Create(pr, pr.SelfRefObject));
var data = await _repository.GetByIdAsync(id, pr => new { pr.SelfRefObjectId });
是否可以模拟该方法,以便它返回指定类型的指定值?
例子
var _repositoryMock = new Mock<IRepository>();
var anonymousReturnValue = new { SelfRefObjectId = 1 };
_repositoryMock
.Setup(pr => pr.GetByIdAsync(
entityId,
pr => new { pr.SelfRefObjectId },
default))
.ReturnsAsync(anonymousReturnValue)
.Verifiable();
var tupleReturnValue = Tuple.Create(new Entity(), new Entity());
_repositoryMock
.Setup(pr => pr.GetByIdAsync(
entityId,
pr => Tuple.Create(pr, pr.SelfRefObject),
default))
.ReturnsAsync(tupleReturnValue)
.Verifiable();
提前致谢。
简而言之:据我所知,你不能这样做。
有两种非常有用的辅助类型: It.IsAnyType
和It.IsSubType<T>
。
在设置阶段,您可以使用它们来告诉您的函数接受任何内容:
_repositoryMock
.Setup(repo => repo.GetByIdAsync(
It.IsAny<int>(),
It.IsAny<Expression<Func<Entity, It.IsAnyType>>>(),
It.IsAny<It.IsAnyType>()))
.Verifiable();
或者它只接受匿名类型或元组:
_repositoryMock
.Setup(repo => repo.GetByIdAsync(
It.IsAny<int>(),
It.Is<Expression<Func<Entity, It.IsAnyType>>>((o, type) => type.IsAnonymousType()),
It.Is<It.IsAnyType>((o, type) => type.IsAnonymousType())))
.Verifiable();
_repositoryMock
.Setup(repo => repo.GetByIdAsync(
It.IsAny<int>(),
It.Is<Expression<Func<Entity, It.IsAnyType>>>((o, type) => type.IsTuple()),
It.Is<It.IsAnyType>((o, type) => type.IsTuple())))
.Verifiable();
辅助方法:
public static class TypeExtension
{
public static bool IsAnonymousType(this Type type)
{
var hasCompilerGeneratedAttribute = type.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Any();
var nameContainsAnonymousType = type.FullName != null && type.FullName.Contains("AnonymousType");
return hasCompilerGeneratedAttribute && nameContainsAnonymousType;
}
public static bool IsTuple(this Type type)
{
if (!type.IsGenericType) return false;
var openType = type.GetGenericTypeDefinition();
return openType == typeof(Tuple<>) || openType == typeof(Tuple<,>)
|| openType == typeof(ValueTuple<>) || openType == typeof(ValueTuple<,>);
}
}
当您需要指定Return/ReturnAsync
部分时,问题就出现了。
_repositoryMock
.Setup(repo => repo.GetByIdAsync(
It.IsAny<int>(),
It.Is<Expression<Func<Entity, It.IsAnyType>>>((o, type) => type.IsTuple()),
It.Is<It.IsAnyType>((o, type) => type.IsTuple())))
.Returns(valueFunction: () => Task.FromResult(tupleReturnValue));
它不会编译,因为它不能将Tuple<Entity, Entity>
转换为Mock.It.IsAnyType
严重性代码描述项目文件行抑制状态错误 CS0029 无法将类型“System.Threading.Tasks.Task<System.Tuple<anonym.Entity, anonym.Entity>>”隐式转换为“System.Threading.Tasks.Task<Moq.It .IsAnyType>'
即使相关的github 问题已关闭,类型解析器似乎也不起作用。
替代方法可以使用DefaultValueProvider
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.