Search code examples
c#unit-testinghttpclientmstesthttpclientfactory

How to mock setup a method to return different value


Below is the piece of code i am trying to write unit test case for CallMethod

public async Task<String> CallMethod(string accountName)
        {
            var response= await GetResponseAsync(Name);

            var finalresponse= await PostReponseAsync(response);

            return finalresponse;
        }
private async Task GetResponseAsync(string Name)
        {
            var param = Name;
            using (var httpClient = _httpClientFactory.CreateClient())
            {

                httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "token");
                var response = await httpClient.GetAsync(URL +"?" + param);
                if (response != null)
                {
                    var responseMessage = await response.Content.ReadAsStringAsync();
                }
            }
        }
private async Task PostReponseAsync(string reponse)
        {
            var json = JsonConvert.SerializeObject(reponse);
            var data = new StringContent(json, Encoding.UTF8, "application/json");

            using (var httpClient = _httpClientFactory.CreateClient())
            {
                httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "token");
                var response = await httpClient.PostAsync(URl, data);
                if (response != null)
                {
                    var responseMessage = await response.Content.ReadAsStringAsync();
                }
            }
        }

Unit Test Method:

[TestMethod]
        public async Task CallMethod()
        {
            // Arrange
            string Name = "Value";
            
            var GetResponseMessage = new HttpResponseMessage
            {
                StatusCode = HttpStatusCode.OK,
                Content = new StringContent("Message1"),
            };
            
            var postResponseMessage = new HttpResponseMessage
            {
                StatusCode = HttpStatusCode.OK,
                Content = new StringContent("Message2"),
            };
            var handlerMock = new Mock<HttpMessageHandler>();
            handlerMock.Protected().SetupSequence<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>()).ReturnsAsync(GetResponseMessage).ReturnsAsync(postResponseMessage);

            var httpClient = new HttpClient(handlerMock.Object);
            _mockHttpClientFactory.Setup(_ => _.CreateClient(It.IsAny<string>())).Returns(httpClient);

            // Act
            var response = await class.CallMethod( accountName);

            // Assert            
        }

For GetResponseAsync method i am getting the reponse but when PostReponseAsync method called it throw exception as given below

Project.CallMethod threw exception: System.ObjectDisposedException: Cannot access a disposed object. Object name: 'System.Net.Http.HttpClient

Can somebody help me out in this.


Solution

  • Mock separate clients from the factory since each method disposes of the client it uses.

    [TestMethod]
    public async Task CallMethod() {
        // Arrange
        string Name = "Value";
        
        var GetResponseMessage = new HttpResponseMessage {
            StatusCode = HttpStatusCode.OK,
            Content = new StringContent("Message1"),
        };
        var getHandlerMock = new Mock<HttpMessageHandler>();
        getHandlerMock.Protected()
            .Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
            .ReturnsAsync(GetResponseMessage);
    
        var postResponseMessage = new HttpResponseMessage {
            StatusCode = HttpStatusCode.OK,
            Content = new StringContent("Message2"),
        };
        var postHandlerMock = new Mock<HttpMessageHandler>();
        postHandlerMock.Protected()
            .Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
            .ReturnsAsync(postResponseMessage);
    
        var getHttpClient = new HttpClient(getHandlerMock.Object);
        var postHttpClient = new HttpClient(postHandlerMock.Object);
    
        _mockHttpClientFactory
            .SetupSequence(_ => _.CreateClient(It.IsAny<string>()))
            .Returns(getHttpClient)
            .Returns(postHttpClient);
    
        // Act
        var response = await class.CallMethod(accountName);
    
        // Assert
        //...      
    }