Reputation: 35
I'm trying to create a Moq test project but I cannot inject the dependencies on the service/interface because my service constructor doesn't have an interface argument.
Service constructor:
public NearEarthObjectService(HttpClient httpClient)
{
_httpClient = httpClient;
}
Project Program.cs:
using NasaApi.Services;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddTransient(sp => new HttpClient { BaseAddress = new Uri("https://api.nasa.gov/neo/rest/v1/") });
builder.Services.AddScoped<INearEarthObjectService, NearEarthObjectService>();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
Empty Moq test project :(
public class NearEarthObjectService_Tests {
public NearEarthObjectService_Tests()
{
}
As can you see, the dependencies in the program are injected in the Startup.cs with the builder.Services.AddScoped
builder.Services.AddScoped<INearEarthObjectService, NearEarthObjectService>();
My controller
[Route("[controller]")]
[ApiController]
public class AsteroidsController : ControllerBase
{
INearEarthObjectService _earthObjectService;
public AsteroidsController(INearEarthObjectService earthObjectService)
{
_earthObjectService = earthObjectService;
}
// GET: <AsteroidsController>
[HttpGet]
public async Task<ActionResult<IEnumerable<NearEarthObjectDTO>>> Get([BindRequired, FromQuery] int days)
{
if (days < 1 || days > 7)
{
return StatusCode(400);
}
else
{
var response = await Task.Run(() => _earthObjectService.GetAllNeos(days));
return Ok(response);
}
}
}
Upvotes: 0
Views: 666
Reputation: 762
You can't mock HttpClient with a mocking library for so far as I know. What you can do is instantiate a new HttpClient in you test and provide a custom HttpMessageHandler to it's contructor. This is what I always do to fake responses for HttpClient calls. It works like this
First create your custom HttpMessageHandler:
public class MyHttpMessageHandler : HttpMessageHandler
{
private readonly HttpResponseMessage fakeRespone;
public MyHttpMessageHandler(HttpResponseMessage fakeRespone)
{
this.fakeRespone = fakeRespone;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
return Task.FromResult(fakeRespone);
}
}
And then instantiate your test like this:
[Fact]
public async void Test1()
{
//Mock the HTTP client
var fakeResponse = new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
};
var httpClient = new HttpClient(new MyHttpMessageHandler(fakeResponse));
//Create System under test
var sut = new ClassToTest(httpClient);
//Call your method
var response = await sut.CallHttpClient(new Uri("http://example.com/somepage"));
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
}
For good measure, this is test class i created for the example:
public class ClassToTest
{
private readonly HttpClient httpClient;
public ClassToTest(HttpClient httpClient)
{
this.httpClient = httpClient;
}
public Task<HttpResponseMessage> CallHttpClient(Uri uri)
{
return httpClient.GetAsync(uri);
}
}
Hope this helps you
Upvotes: 2