在 .Net Core 3.1 中使用 Moq 模拟委托时出现问题
Problem mocking delegate with Moq in .Net Core 3.1
我在模拟 returns 和 IHttpClient
的代表时遇到问题。这是客户的要求,我不能更改实现。
代码看起来像这样:
代表:
namespace Foo.Http
{
public delegate IHttpClient FooHttpClientProvider(string name);
}
测试class:
[SetUp]
public void SetUp()
{
Mock<FooHttpClientProvider>().Setup(x => x("HttpClient")).Returns(Mock<IHttpClient>().Object);
}
当我这样做时,出现以下异常:
System.InvalidCastException : Unable to cast object of type 'Foo.Http.FooHttpClientProvider' to type 'Moq.IMocked`1[Foo.Http.FooHttpClientProvider]'.
有什么想法吗?这甚至可能吗?
编辑: 一些额外信息:我需要测试的服务被注入了 FooHttpClientProvider。我们使用带有 Autofac 的全局 Mock 来注册我们需要的服务。由于我无法将提供程序作为参数传递,因此我无法为 FooHttpClientProvider 实例化一个新的 Mock 并将其作为参数传递给我的服务;我需要在全球模拟中设置它。这使事情更加复杂。
服务代码如下所示:
private readonly FooHttpClientProvider _client;
public FooService(
FooHttpClientProvider fooClient)
{
_client = fooClient("HttpClient");
}
public async Task<OutputDto> GetAsync(Request request)
{
var accessToken = await _AuthService.GetAccessTokenAsync();
try
{
var response =
await ExecuteGet<OutputDto>(
$"{FooConfig.BaseUrl}someEntpoint{GetQueryParams(request)}", accessToken);
return response;
}
catch(Exception ex)
{
//Exception handling
}
}
服务本身运行正常。只有在尝试模拟它进行单元测试时才会出现问题。
这很可能是 XY problem。
无需模拟委托。使用 return 模拟 IHttpClient
的实际委托
[SetUp]
public void SetUp() {
Mock<IHttpClient> clientMock = new Mock<IHttpClient>();
//... set up the client mock to behave as needed
FooHttpClientProvider provider = (string name) => clientMock.Object;
//... use created delegate as needed with the subject under test
FooService subject = new FooService(provider);
}
调用主体的构造函数的地方
//...
public FooService(FooHttpClientProvider fooClient) {
_client = fooClient("HttpClient");
//...
}
//...
在测试中创建的委托将调用并且 return 模拟的 IHttpClient
我能够解决这个问题。事实证明,将 IHttpClient 模拟到我的全局 Mock 对象中,仅此一项就足以带走我的 DI 容器。工作得很好。
我在模拟 returns 和 IHttpClient
的代表时遇到问题。这是客户的要求,我不能更改实现。
代码看起来像这样:
代表:
namespace Foo.Http
{
public delegate IHttpClient FooHttpClientProvider(string name);
}
测试class:
[SetUp]
public void SetUp()
{
Mock<FooHttpClientProvider>().Setup(x => x("HttpClient")).Returns(Mock<IHttpClient>().Object);
}
当我这样做时,出现以下异常:
System.InvalidCastException : Unable to cast object of type 'Foo.Http.FooHttpClientProvider' to type 'Moq.IMocked`1[Foo.Http.FooHttpClientProvider]'.
有什么想法吗?这甚至可能吗?
编辑: 一些额外信息:我需要测试的服务被注入了 FooHttpClientProvider。我们使用带有 Autofac 的全局 Mock 来注册我们需要的服务。由于我无法将提供程序作为参数传递,因此我无法为 FooHttpClientProvider 实例化一个新的 Mock 并将其作为参数传递给我的服务;我需要在全球模拟中设置它。这使事情更加复杂。
服务代码如下所示:
private readonly FooHttpClientProvider _client;
public FooService(
FooHttpClientProvider fooClient)
{
_client = fooClient("HttpClient");
}
public async Task<OutputDto> GetAsync(Request request)
{
var accessToken = await _AuthService.GetAccessTokenAsync();
try
{
var response =
await ExecuteGet<OutputDto>(
$"{FooConfig.BaseUrl}someEntpoint{GetQueryParams(request)}", accessToken);
return response;
}
catch(Exception ex)
{
//Exception handling
}
}
服务本身运行正常。只有在尝试模拟它进行单元测试时才会出现问题。
这很可能是 XY problem。
无需模拟委托。使用 return 模拟 IHttpClient
[SetUp]
public void SetUp() {
Mock<IHttpClient> clientMock = new Mock<IHttpClient>();
//... set up the client mock to behave as needed
FooHttpClientProvider provider = (string name) => clientMock.Object;
//... use created delegate as needed with the subject under test
FooService subject = new FooService(provider);
}
调用主体的构造函数的地方
//...
public FooService(FooHttpClientProvider fooClient) {
_client = fooClient("HttpClient");
//...
}
//...
在测试中创建的委托将调用并且 return 模拟的 IHttpClient
我能够解决这个问题。事实证明,将 IHttpClient 模拟到我的全局 Mock 对象中,仅此一项就足以带走我的 DI 容器。工作得很好。