Problema de burla de delegado con Moq en .Net Core 3.1
Estoy teniendo problemas al hacer una simulación de un delegado que devuelve un IHttpClient
. Esto es requerido por el cliente y no puedo cambiar la implementación.
El código se ve algo así:
Delegado:
namespace Foo.Http
{
public delegate IHttpClient FooHttpClientProvider(string name);
}
Clase de prueba:
[SetUp]
public void SetUp()
{
Mock<foohttpclientprovider>().Setup(x => x("HttpClient")).Returns(Mock<ihttpclient>().Object);
}
Cuando hago esto, obtengo la siguiente excepción:
System.InvalidCastException: No se puede convertir el objeto del tipo ‘Foo.Http.FooHttpClientProvider’ al tipo ‘Moq.IMocked`1[Foo.Http.FooHttpClientProvider]’.
¿Algún idea? ¿Es esto siquiera posible?
Editar: Algunos datos adicionales: el servicio que necesito probar recibe un FooHttpClientProvider inyectado. Usamos un Mock global con Autofac que registra los servicios que necesitamos. Dado que no puedo pasar el proveedor como parámetro, no puedo crear un nuevo Mock para FooHttpClientProvider y pasarlo a mi servicio como parámetro; necesito configurarlo en el mock global. Esto complica aún más las cosas.
El código del servicio se ve algo así:
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)
{
// Manejo de excepciones
}
}
El servicio en sí funciona correctamente. El problema surge solo al intentar hacer una simulación (mock) para pruebas unitarias.
davy.ai
Parece que el problema está en el tipo del objeto que estás simulando. El método
Mock<t>()
crea un objetoMoq.IMocked<t>
, que es diferente al tipoFooHttpClientProvider
.En lugar de simular directamente el delegado, podrías crear una instancia de
FooHttpClientProvider
y pasarla a tu servicio como parámetro. Luego, en la configuración de tu prueba, puedes crear una simulación deIHttpClient
y pasarlo a la instancia deFooHttpClientProvider
.Aquí tienes un ejemplo:
En este ejemplo, creamos una simulación de
IHttpClient
y la pasamos aCreateFooHttpClientProvider()
, que devuelve una instancia deFooHttpClientProvider
. Esta instancia devolverá la simulación deIHttpClient
cuando se le pase el nombre “HttpClient”.Luego, pasamos la instancia de
FooHttpClientProvider
al constructor deFooService
, que la utilizará para obtener la instancia deIHttpClient
para realizar las solicitudes HTTP. Por último, llamamos al métodoGetAsync()
y aseguramos que devuelve unOutputDto
no nulo.Esto debería permitirte simular el delegado y probar tu servicio sin cambiar la implementación.