3

I have webapi where it needs to call some other endpoint and get data.

My current code as follows

//http client implementation

public interface IHttpClientFactory { HttpClient Create(); } public class HttpClientFactory : IHttpClientFactory { private readonly ApplicationSettings _applicationSettings; HttpClient _httpClient; public HttpClientFactory(IOptions<ApplicationSettings> settings) { _applicationSettings = settings.Value; } public HttpClient Create() { if (_httpClient != null) return _httpClient; var client = new HttpClient() { BaseAddress = new Uri($"{_applicationSettings.BaseUrl}") }; _httpClient = client; return _httpClient; } } public interface IGetItemsQuery { Task<IEnumerable<T>> Execute<T>(string url); } public class GetItemQuery: IGetItemsQuery { private readonly IHttpClientFactory _httpClientFactory; public GetPhotosQuery(IHttpClientFactory httpClientFactory) { _httpClientFactory = httpClientFactory; } public async Task<IEnumerable<T>> Execute<T>(string url) { using (var response = await _httpClientFactory.Create().GetAsync($"{url}").ConfigureAwait(false)) { response.EnsureSuccessStatusCode(); var resp = await response.Content.ReadAsStringAsync().ConfigureAwait(false); var items = JArray.Parse(resp); return items.ToObject<T[]>(); } } 

In my controller part

 private readonly IGetItemsQuery _getItemsQuery; public HomeController(IGetItemsQuery getItemsQuery) { _getItemsQuery = getItemsQuery; } appsettings "ApplicationSettings": { "BaseUrl": "http://someendpoint.com/" 

}

Startup

 services.Configure<ApplicationSettings>(Configuration.GetSection("ApplicationSettings")); services.AddScoped<IGetItemsQuery, GetPhotosQuery>(); services.AddScoped<IHttpClientFactory, HttpClientFactory>(); 

I want to try something like below in my test

 [Fact] public void Test_Index() { // Arrange var itemsQuery = new Mock<IGetItemsQuery>(); var controller = new HomeController(itemsQuery.Object); // Act var result = controller.Index(); // Assert var viewResult = Assert.IsType<ViewResult>(result); Assert.Null(viewResult.ViewName); } 

This is creating mock IGetItemsQuery but this isn't mocking the actual IHttpClientFactory.

Is there a way to do this

0

1 Answer 1

3

Based on your design with the abstracted dependencies there would be no need to mock a client factory in order to unit test the controller.

As you have done in your test, you mock IGetItemsQuery, but you have not set it up to behave as expected when invoked in the test.

If, for example, the controller method under test look something like this

private readonly IGetItemsQuery getItemsQuery; public HomeController(IGetItemsQuery getItemsQuery) { this.getItemsQuery = getItemsQuery; } public async Task<IActionResult> Index() { var url = "...."; var items = await getItemsQuery.Execute<MyItem>(url); return View(items); } 

Then an isolated unit test for the Index action as the method under test could look something like

[Fact] public async Task Index_Should_Return_View_With_Items() { // Arrange var itemsQuery = new Mock<IGetItemsQuery>(); var items = new MyItem[] { new MyItem(), new MyItem() }; itemsQuery.Setup(_ => _.Execute<MyItem>(It.IsAny<string>())) .ReturnsAsync(items); var controller = new HomeController(itemsQuery.Object); // Act var result = await controller.Index(); // Assert var viewResult = Assert.IsType<ViewResult>(result); Assert.Null(viewResult.ViewName); } 
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.