首页 > 其他分享 >HttpClient mock

HttpClient mock

时间:2022-12-22 11:44:30浏览次数:56  
标签:will our var new mock HttpClient

How to Mock HttpClient with Unit Tests in C# - Code Maze (code-maze.com)

 

Mocking HTTP requests for unit testing is important because of the prevalence of APIs in modern software development. In this article, we will show you how to mock HttpClient and compare two ways to mock HTTP requests in our unit tests. We will use Moq to mock a HttpMessageHandler, and  also, we will analyze mocking HttpClient by using the MockHttp NuGet package.

To download the source code for this article, you can visit our GitHub repository.

Let’s start.

Mock HttpMessageHandler Using Moq

Trying to unit test the code that utilizes HttpClient, we might initially want to mock that HttpClient. Mocking HttpClient is possible although an arduous task. Luckily there is still a great way to unit test the code. The solution is to mock HttpMessageHandler and pass this object to the HttpClient constructor. When we use the message handler to make HTTP requests, we achieve our unit testing goals.

By providing our own message handler we can return whatever HttpResponseMessage we want. Using Moq makes this process easier as we do not have to implement our own class for each response. Mocking HttpMessageHandler is simple as there is only one, protected SendAsync() method . Importing the Moq.Protected namespace allows us to mock protected methods with the Protected() method.

That said, let’s take a look at our unit test:

 

[TestMethod] public async Task GivenMockedHandler_WhenRunningMain_ThenHandlerResponds() { var mockedProtected = _msgHandler.Protected();   var setupApiRequest = mockedProtected.Setup<Task<HttpResponseMessage>>( "SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>() );   var apiMockedResponse = setupApiRequest.ReturnsAsync(new HttpResponseMessage() { StatusCode = HttpStatusCode.OK, Content = new StringContent("mocked API response") }); }

We mock a call to the SendAsync() function and provide a response to return with the ReturnAsync()method. In the Setup<>() method, the first parameter is the name of the method that is being mocked. Next, we match each parameter to the "SendAsync" method with an expression. In this case, we are using the ItExpr.IsAny<> method to match any HttpRequestMessage object. Finally we, again, use ItExpr.IsAny<> to match any CancellationToken object.

In ReturnAsync(), we provide an object that will be the return value of the mocked function in Setup(). Later in this article, we will look at how we can refine our ItExpr to match more specific parameters rather than any parameter of the right type.

Now, let’s take a look at what the code that we want to test looks like:

 

public static HttpMessageHandler? Handler { get; set; } public static HttpClient Client = new HttpClient();   public static async Task Main(string[] args) { if (Handler is not null) { Client = new HttpClient(Handler); } string baseAddress = "https://reqres.in"; string apiEndpoint = "/api/users/2";   await var responseMessage = Client.GetAsync(baseAddress + apiEndpoint); }

We can see we are providing the client instance handler that during a unit test will be a mocked handler. During unit testing, the value returned by GetAsync() will be the value we provide to ReturnsAsync() during setup.

Matching Specific HTTP Requests

While our previous example is great for testing simple code it will not suffice to test code that will call multiple API endpoints with the same HttpClient. This is because of the way we set up the mock message handler to return the same response for any HttpRequestMessage. To change this solution to test more complex code, we must refine each setup to match more specific parameters:

 

var mockedProtected = _msgHandler.Protected();   var setupApiRequest = mockedProtected.Setup<Task<HttpResponseMessage>>( "SendAsync", ItExpr.Is<HttpRequestMessage>(m => m.RequestUri!.Equals(_baseAddress + _apiEndpoint)), ItExpr.IsAny<CancellationToken>());   var apiMockedResponse = setupApiRequest .ReturnsAsync(new HttpResponseMessage() { StatusCode = HttpStatusCode.OK, Content = new StringContent("mocked API response") });

Using ItExpr.Is<>() allows us to match more specific objects rather than any object of a type. In our example, we are specifically matching any HttpRequestMessage that satisfies the m => m.RequestUri!.Equals(apiUriEndpoint) expression. This means that the mock handler is prepared for any HTTP request to a specific API endpoint. We can further refine this setup by adding to the expression. There are other HttpRequestMessage properties we can work with. We can try to match requests on these properties: RequestUriContentHeadersMethod, and Version. For example, we can create a setup with an expression that matches a certain RequestUri, carrying a specific Content object, and a specific request Headers.

Mock HttpClient Using MockHttp

MockHttp is a wonderful tool that allows us to similarly mock the message handler for HttpClient in a more feature-complete package. Let’s explore this further after installing it into our project:

 

 

Install-Package RichardSzalay.MockHttp

 

We can begin using this package by adding using RichardSzalay.MockHttp to our code. 

There are two methods we can use to set up an API request: When() and Expect(). Calling When() will create a backend definition. Calling Expect() will create a request expectation.

 

 

A backend definition can be matched multiple times, but MockHttp will not match any backend definitions when there are any outstanding request expectations. This behavior can be changed using BackendDefinitionBehavior.Always into the MockHttpMessageHandler constructor.

A request expectation can be matched only once and request expectations are matched in the order they were added. These two facts are the major differences in behavior compared to backend definitions. The default behavior for MockHttpMessageHandler is to match all request expectations before matching any backend definitions. You can verify there are no outstanding request expectations by calling the VerifyNoOutstandingExpectation() method:

 

_msgHandler = new MockHttpMessageHandler(); _msgHandler.When("https://reqres.in/api/users/*").Respond("text/plain", "mocked user response");

In this example, we can see one feature MockHttp offers that mocking the message handler ourselves does not have. The wildcard character can be used to match many different API endpoints. 

There are several utility methods MockHttp offers to manage definitions and expectations. Clear() will delete all definitions and expectations. Flush() will complete all pending requests when the AutoFlush property is falseResetBackendDefinitions() and ResetExpections() will clear their respective request types. Lastly, ToHttpClient() is a great function to produce an HttpClient that includes our mocked message handler.

Matching Specific HTTP Requests

The When()With(), and Expect() methods return MockedRequest objects. MockedRequest objects can be further constrained with matchers. 

Let’s consider the next example where we constrain a match on an expectation:

 

_msgHandler.Expect("https://reqres.in/api/users/*") .WithHeaders(@"Authorization: Basic abcdef") .WithQueryString("Id=2&Version=12") .Respond("text/plain", "mocked response");

We use this expectation to add constraints on Url, headers defining Basic authorization, and the query containing specific Id and Version key-value pairs. MockHttp offers multiple matchers that can be added to constrain a request match based on: Query, Form Data, Content, and Headers.

To learn more about MockHttp visit the GitHub here

 

 

Conclusion

In this article, we’ve learned how to mock HttpClient in our C# code. Mocking our own message handler offers a quick and basic way to perform this mocking. It would serve as a great basis to write more complex unit testing solutions for projects. On the other hand, MockHttp offers many great features out of the box. This enables us to write robust unit tests quickly. Learning to use a new tool can be challenging but rewarding. MockHttp will allow us to spend more time writing robust tests rather than fighting with writing our own implementation of a mocked message handler.

 

 

How to test HttpClient with Moq in C# - DEV Community

标签:will,our,var,new,mock,HttpClient
From: https://www.cnblogs.com/panpanwelcome/p/16998053.html

相关文章

  • 或许是市面上最强的 Mock 工具
    背景在开发过程中,由于后端与前端并行开发,或者前端需要等待后台开发,难以保证对接效率,同时即使用开发好的API对接,也有可能一个API不通就阻塞了整个软件的对接工作。......
  • agv_fastapi_socket_mock
    E:\song\agv_fastapi_socket_v4_mock\app.pyimporttimefromfastapiimportFastAPI,WebSocket,Request,WebSocketDisconnectfromfastapi.responsesimportRedire......
  • HttpClient Timeout waiting for connection from pool 问题解决方案
    错误:org.apache.http.conn.ConnectionPoolTimeoutException:Timeoutwaitingforconnectionfrompool前言:第一次看到这个错误,上网找了下,有文章说是连接池不够了。。。......
  • SAP UI5 Mock Server 在响应 OData 请求时的单步调试
    SAPUI5中包含的模拟服务器模仿ODataV2后端调用。它模拟OData提供程序并且完全基于客户端,这意味着不需要与远程主机的网络连接。它拦截对服务器的HTTP调用,并向客......
  • Hamcrest、Mockito 专题
    UT中需要的jarJunit4.1X.jarhamcrest-library-1.x.jarhamcrest-core-l.x.jarmockito-all-1.10.x.jar Junit使用hamcrest的Matcher找不到的问题(比如greaterThan)问题:用junit......
  • 使用mockjs模拟数据
    相关介绍在常见的前后端开发模式中,经常因为一些接口的问题导致工程效率低。作为前端开发者我们有时候可以使用mockjs来模拟后端的接口,只需要做到模拟就行,主要是用来检测我......
  • 0基础→自动化测试框架实现:java + testng + httpclient + allure
    必备基础java基础配置文件解析(properties)fastjson的使用(处理json字符串、json数组)jsonpath的使用java操作excel(通过POIHttpClient的使用(get、post请求)TestNG用法 自动化测......
  • [Java SE/Junit] 基于Java的单元测试框架Mockito[转载]
    Mockito是一个模拟测试框架,主要功能是在单元测试中模拟类/对象的行为。1为什么要使用Mockito?Mock可以理解为创建一个虚假的对象,或者说模拟出一个对象.在测试环境中用......
  • Mocks Aren't Stubs
    Theterm'MockObjects'hasbecomeapopularonetodescribespecialcaseobjectsthatmimicrealobjectsfortesting.Mostlanguageenvironmentsnowhaveframe......
  • 全栈开发提效神器——ApiFox(Postman + Swagger + Mock + JMeter)
    一、ApiFox简介介绍:ApiFox是一款集成了API文档、API调试、APIMock、API自动化测试等多种功能于一身的一体化协作平台。功能定位:​​Apifox=Postman+Swagger+Mock......