public static async Task Use_With_Refit() { // Arrange var builder = new HttpRequestInterceptionBuilder() .ForHttps() .ForHost("api.github.com") .ForPath("orgs/justeat") .WithJsonContent(new { id = 1516790, login = "******", url = "https://api.github.com/orgs/justeat" }); var options = new HttpClientInterceptorOptions().Register(builder); var service = RestService.For <IGitHub>(options.CreateHttpClient("https://api.github.com")); // Act Organization actual = await service.GetOrganizationAsync("justeat"); // Assert actual.ShouldNotBeNull(); actual.Id.ShouldBe(1516790); actual.Login.ShouldBe("justeat"); actual.Url.ShouldBe("https://api.github.com/orgs/justeat"); }
public static async Task SendAsync_Throws_If_Registration_Missing_Post() { // Arrange var options = new HttpClientInterceptorOptions() .ThrowsOnMissingRegistration(); var mock = new Mock <HttpMessageHandler>(); using var handler = options.CreateHttpMessageHandler(); using var target = new HttpClient(handler); using var content = new StringContent(string.Empty); // Act var exception = await Should.ThrowAsync <HttpRequestNotInterceptedException>( () => target.PostAsync("https://google.com/", content)); // Assert exception.Message.ShouldBe("No HTTP response is configured for POST https://google.com/."); exception.Request.ShouldNotBeNull(); exception.Request.RequestUri.ShouldBe(new Uri("https://google.com/")); }
/// <summary> /// Registers one or more HTTP request interceptions, replacing any existing registrations. /// </summary> /// <param name="options">The <see cref="HttpClientInterceptorOptions"/> to set up.</param> /// <param name="collection">A collection of <see cref="HttpRequestInterceptionBuilder"/> instances to use to create the registration(s).</param> /// <returns> /// The current <see cref="HttpClientInterceptorOptions"/>. /// </returns> /// <exception cref="ArgumentNullException"> /// <paramref name="options"/> or <paramref name="collection"/> is <see langword="null"/>. /// </exception> public static HttpClientInterceptorOptions Register( this HttpClientInterceptorOptions options, IEnumerable <HttpRequestInterceptionBuilder> collection) { if (options == null) { throw new ArgumentNullException(nameof(options)); } if (collection == null) { throw new ArgumentNullException(nameof(collection)); } foreach (var builder in collection) { options.Register(builder); } return(options); }
public static async Task Intercept_Http_Delete() { // Arrange var builder = new HttpRequestInterceptionBuilder() .ForDelete() .ForHttps() .ForHost("public.je-apis.com") .ForPath("baskets/123/orderitems/456") .WithStatus(HttpStatusCode.NoContent); var options = new HttpClientInterceptorOptions() .Register(builder); using var client = options.CreateHttpClient(); // Act using var response = await client.DeleteAsync("https://public.je-apis.com/baskets/123/orderitems/456"); // Assert response.StatusCode.ShouldBe(HttpStatusCode.NoContent); }
public static async Task GetResponseAsync_Returns_Empty_Response_If_ContentStream_Returns_Null_Asynchronous() { // Arrange var method = HttpMethod.Get; var uri = new Uri("https://google.com/"); var options = new HttpClientInterceptorOptions() .RegisterStream(method, uri, () => Task.FromResult <Stream>(null)); var request = new HttpRequestMessage(method, uri); // Act HttpResponseMessage actual = await options.GetResponseAsync(request); // Assert actual.ShouldNotBeNull(); actual.RequestMessage.ShouldBe(request); actual.Content.ShouldNotBeNull(); actual.Content.Headers?.ContentLength.ShouldBe(0); actual.Content.Headers?.ContentType?.MediaType.ShouldBe("application/json"); }
private static HttpClient CreateClient() { var options = new HttpClientInterceptorOptions(); new HttpRequestInterceptionBuilder() .Requests() .ForHttps() .ForHost("findalearningaimbeta.fasst.org.uk") .ForPath("DownloadData/GetDownloadFileAsync") .ForQuery("fileName=published%2F007%2FLearningDelivery_V007_CSV.Zip") .Responds() .WithContentHeader("Content-Type", "application/zip") .WithContentStream(() => { var resourceName = $"{typeof(LarsDataImporterTests).Namespace}.LARS.zip"; return(typeof(LarsDataImporterTests).Assembly.GetManifestResourceStream(resourceName)); }) .RegisterWith(options); return(options.CreateHttpClient()); }
public async Task GetById_ItemDoesNotExist_ReturnsNull() { // Arrange var options = new HttpClientInterceptorOptions(); new HttpRequestInterceptionBuilder() .Requests() .ForHttps() .ForHost("services.postcodeanywhere.co.uk") .ForPath("PostcodeAnywhere/Interactive/RetrieveById/v1.30/json3.ws") .IgnoringQuery() .Responds() .WithJsonContent(new { Items = new[] { new { Error = "1002", Description = "Id Invalid", Cause = "The Id parameter was not valid.", Resolution = "The Id parameter should be an Id from a Find method. It may contain unusual formatting characters, all of which must be presented." } } }) .RegisterWith(options); var httpClient = options.CreateHttpClient(); var service = new LoqateAddressSearchService(httpClient, new Options() { Key = "key" }); // Act var result = await service.GetById("123456.0"); // Assert Assert.Null(result); }
/// <summary> /// Registers an HTTP request interception, replacing any existing registration. /// </summary> /// <param name="options">The <see cref="HttpClientInterceptorOptions"/> to set up.</param> /// <param name="method">The HTTP method to register an interception for.</param> /// <param name="uri">The request URI to register an interception for.</param> /// <param name="contentFactory">A delegate to a method that returns the raw response content.</param> /// <param name="statusCode">The optional HTTP status code to return.</param> /// <param name="mediaType">The optional media type for the content-type.</param> /// <param name="responseHeaders">The optional HTTP response headers.</param> /// <returns> /// The current <see cref="HttpClientInterceptorOptions"/>. /// </returns> /// <exception cref="ArgumentNullException"> /// <paramref name="options"/>, <paramref name="method"/>, <paramref name="uri"/> or /// <paramref name="contentFactory"/> is <see langword="null"/>. /// </exception> public static HttpClientInterceptorOptions RegisterByteArray( this HttpClientInterceptorOptions options, HttpMethod method, Uri uri, Func <byte[]> contentFactory, HttpStatusCode statusCode = HttpStatusCode.OK, string mediaType = HttpClientInterceptorOptions.JsonMediaType, IEnumerable <KeyValuePair <string, string> >?responseHeaders = null) { if (options == null) { throw new ArgumentNullException(nameof(options)); } if (contentFactory == null) { throw new ArgumentNullException(nameof(contentFactory)); } IDictionary <string, IEnumerable <string> >?multivalueHeaders = null; if (responseHeaders != null) { multivalueHeaders = new Dictionary <string, IEnumerable <string> >(); foreach (var pair in responseHeaders) { multivalueHeaders[pair.Key] = new[] { pair.Value }; } } return(options.RegisterByteArray( method, uri, () => Task.FromResult(contentFactory()), statusCode, mediaType, multivalueHeaders)); }
public static async Task GetResponseAsync_Returns_Empty_Response_If_Custom_Response_Header_Is_Null() { // Arrange var method = HttpMethod.Get; var uri = new Uri("https://google.com/"); IDictionary <string, string> responseHeaders = null; var options = new HttpClientInterceptorOptions() .RegisterByteArray(method, uri, contentFactory: Array.Empty <byte>, responseHeaders: responseHeaders); var request = new HttpRequestMessage(method, uri); // Act HttpResponseMessage actual = await options.GetResponseAsync(request); // Assert actual.ShouldNotBeNull(); actual.RequestMessage.ShouldBe(request); actual.Content.ShouldNotBeNull(); actual.Content.Headers.ContentLength.ShouldBe(0); }
public static async Task Use_The_Same_Builder_For_Multiple_Registrations_On_The_Same_Host() { // Arrange var options = new HttpClientInterceptorOptions(); // Configure a response for https://api.github.com/orgs/justeat var builder = new HttpRequestInterceptionBuilder() .ForHttps() .ForHost("api.github.com") .ForPath("orgs/justeat") .WithJsonContent(new { id = 1516790, login = "******", url = "https://api.github.com/orgs/justeat" }); options.Register(builder); // Update the same builder to configure a response for https://api.github.com/orgs/dotnet builder.ForPath("orgs/dotnet") .WithJsonContent(new { id = 9141961, login = "******", url = "https://api.github.com/orgs/dotnet" }); options.Register(builder); var service = RestService.For <IGitHub>(options.CreateHttpClient("https://api.github.com")); // Act Organization justEatOrg = await service.GetOrganizationAsync("justeat"); Organization dotnetOrg = await service.GetOrganizationAsync("dotnet"); // Assert justEatOrg.ShouldNotBeNull(); justEatOrg.Id.ShouldBe(1516790); justEatOrg.Login.ShouldBe("justeat"); justEatOrg.Url.ShouldBe("https://api.github.com/orgs/justeat"); // Assert dotnetOrg.ShouldNotBeNull(); dotnetOrg.Id.ShouldBe(9141961); dotnetOrg.Login.ShouldBe("dotnet"); dotnetOrg.Url.ShouldBe("https://api.github.com/orgs/dotnet"); }
public static async Task Can_Intercept_Http_Requests_From_Bundle_File() { // Arrange var options = new HttpClientInterceptorOptions().ThrowsOnMissingRegistration(); var headers = new Dictionary <string, string>() { { "accept", "application/vnd.github.v3+json" }, { "authorization", "token my-token" }, { "user-agent", "My-App/1.0.0" }, }; // Act options.RegisterBundle(Path.Join("Bundles", "http-request-bundle.json")); // Assert await HttpAssert.GetAsync(options, "https://www.just-eat.co.uk/", mediaType : "text/html"); await HttpAssert.GetAsync(options, "https://www.just-eat.co.uk/order-history"); await HttpAssert.GetAsync(options, "https://api.github.com/orgs/justeat", headers : headers, mediaType : "application/json"); }
public static async Task Inject_Latency_For_Http_Get_With_Cancellation() { // Arrange var latency = TimeSpan.FromMilliseconds(50); var builder = new HttpRequestInterceptionBuilder() .ForHost("www.google.co.uk") .WithInterceptionCallback(async(_, token) => { try { await Task.Delay(latency, token); } catch (TaskCanceledException) { // Ignored } finally { // Assert token.IsCancellationRequested.ShouldBeTrue(); } }); var options = new HttpClientInterceptorOptions() .Register(builder); using var cts = new CancellationTokenSource(TimeSpan.Zero); using var client = options.CreateHttpClient(); // Act await Should.ThrowAsync <TaskCanceledException>( () => client.GetAsync("http://www.google.co.uk", cts.Token)); // Assert cts.IsCancellationRequested.ShouldBeTrue(); }
public static async Task Intercept_Custom_Http_Method() { // Arrange var builder = new HttpRequestInterceptionBuilder() .ForMethod(new HttpMethod("custom")) .ForHost("custom.domain.com") .ForQuery("length=2") .WithContent(() => new byte[] { 0, 1 }); var options = new HttpClientInterceptorOptions() .Register(builder); using var client = options.CreateHttpClient(); using var message = new HttpRequestMessage(new HttpMethod("custom"), "http://custom.domain.com?length=2"); // Act using var response = await client.SendAsync(message); byte[] content = await response.Content.ReadAsByteArrayAsync(); // Assert content.ShouldBe(new byte[] { 0, 1 }); }
public static async Task Intercept_Http_Get_To_Stream_Content_From_Disk() { // Arrange var builder = new HttpRequestInterceptionBuilder() .ForHost("xunit.github.io") .ForPath("settings.json") .WithContentStream(() => File.OpenRead("xunit.runner.json")); var options = new HttpClientInterceptorOptions() .Register(builder); using var client = options.CreateHttpClient(); // Act string json = await client.GetStringAsync("http://xunit.github.io/settings.json"); // Assert json.ShouldNotBeNullOrWhiteSpace(); var config = JObject.Parse(json); config.Value <string>("methodDisplay").ShouldBe("method"); }
public static async Task Can_Intercept_Http_Requests_From_Bundle_File_With_Templated_String_With_User_Template_Values() { // Arrange var options = new HttpClientInterceptorOptions().ThrowsOnMissingRegistration(); var headers = new Dictionary <string, string>() { { "user-agent", "My-Other-App/1.0.0" }, }; var templateValues = new Dictionary <string, string>() { { "ApplicationName", "My-Other-App" }, }; // Act options.RegisterBundle(Path.Join("Bundles", "templated-bundle-string.json"), templateValues); // Assert string content = await HttpAssert.GetAsync(options, "https://www.just-eat.co.uk/", headers : headers); content.ShouldBe("<html><head><title>Just Eat</title></head></html>"); }
public static async Task Use_Multiple_Registrations() { // Arrange var justEat = new HttpRequestInterceptionBuilder() .ForHttps() .ForHost("api.github.com") .ForPath("orgs/justeat") .WithJsonContent(new { id = 1516790, login = "******", url = "https://api.github.com/orgs/justeat" }); var dotnet = new HttpRequestInterceptionBuilder() .ForHttps() .ForHost("api.github.com") .ForPath("orgs/dotnet") .WithJsonContent(new { id = 9141961, login = "******", url = "https://api.github.com/orgs/dotnet" }); var options = new HttpClientInterceptorOptions() .Register(justEat, dotnet); var service = RestService.For <IGitHub>(options.CreateHttpClient("https://api.github.com")); // Act Organization justEatOrg = await service.GetOrganizationAsync("justeat"); Organization dotnetOrg = await service.GetOrganizationAsync("dotnet"); // Assert justEatOrg.ShouldNotBeNull(); justEatOrg.Id.ShouldBe(1516790); justEatOrg.Login.ShouldBe("justeat"); justEatOrg.Url.ShouldBe("https://api.github.com/orgs/justeat"); // Assert dotnetOrg.ShouldNotBeNull(); dotnetOrg.Id.ShouldBe(9141961); dotnetOrg.Login.ShouldBe("dotnet"); dotnetOrg.Url.ShouldBe("https://api.github.com/orgs/dotnet"); }
public HttpClientInterceptionFilter(HttpClientInterceptorOptions options) { _options = options; }
/// <summary> /// Initializes a new instance of the <see cref="InterceptingHttpMessageHandler"/> class. /// </summary> /// <param name="options">The <see cref="HttpClientInterceptorOptions"/> to use.</param> /// <param name="innerHandler">The inner <see cref="HttpMessageHandler"/>.</param> /// <exception cref="ArgumentNullException"> /// <paramref name="options"/> is <see langword="null"/>. /// </exception> public InterceptingHttpMessageHandler(HttpClientInterceptorOptions options, HttpMessageHandler innerHandler) : base(innerHandler) { _options = options ?? throw new ArgumentNullException(nameof(options)); }
public async Task GetById_WithValidRequest_ReturnsParsedResult() { // Arrange var httpRequestInterceptor = new HttpClientInterceptorOptions(); new HttpRequestInterceptionBuilder() .Requests() .ForHttps() .ForHost("api.getaddress.io") .ForPath("find/XX2 00X") .ForQuery("api-key=key&expand=true&sort=true") .Responds() .WithJsonContent(new { postcode = "XX2 00X", latitude = 51.39020538330078, longitude = -0.1320359706878662, addresses = new[] { new { formatted_address = new[] { "658 Mitcham Road", "", "", "Croydon", "Surrey" }, thoroughfare = "Mitcham Road", building_name = "", sub_building_name = "", sub_building_number = "", building_number = "658", line_1 = "658 Mitcham Road", line_2 = "", line_3 = "", line_4 = "", locality = "", town_or_city = "Croydon", county = "Surrey", district = "Croydon", country = "England" }, new { formatted_address = new[] { "660 Mitcham Road", "", "", "Croydon", "Surrey" }, thoroughfare = "Mitcham Road", building_name = "", sub_building_name = "", sub_building_number = "", building_number = "660", line_1 = "660 Mitcham Road", line_2 = "", line_3 = "", line_4 = "", locality = "", town_or_city = "Croydon", county = "Surrey", district = "Croydon", country = "England" }, new { formatted_address = new[] { "Lanfranc School House", "Mitcham Road", "", "Croydon", "Surrey" }, thoroughfare = "Mitcham Road", building_name = "", sub_building_name = "Lanfranc School House", sub_building_number = "", building_number = "", line_1 = "Lanfranc School House", line_2 = "Mitcham Road", line_3 = "", line_4 = "", locality = "", town_or_city = "Croydon", county = "Surrey", district = "Croydon", country = "England" } } }) .RegisterWith(httpRequestInterceptor); var httpClient = httpRequestInterceptor.CreateHttpClient(); var options = new Mock <IOptions <GetAddressAddressSearchServiceOptions> >(); options.Setup(s => s.Value).Returns(new GetAddressAddressSearchServiceOptions { Key = "key" }); var service = new GetAddressAddressSearchService(httpClient, options.Object); // Act var result = await service.GetById($"XX2 00X::{"660 Mitcham Road".GetHashCode():X}"); // Assert Assert.NotNull(result); Assert.Equal("660 Mitcham Road", result.Line1); Assert.Equal("", result.Line2); Assert.Equal("", result.Line3); Assert.Equal("", result.Line4); Assert.Equal("Croydon", result.PostTown); Assert.Equal("Surrey", result.County); Assert.Equal("XX2 00X", result.Postcode); Assert.Equal("England", result.CountryName); }
protected FunctionTests(ITestOutputHelper outputHelper) { OutputHelper = outputHelper; Interceptor = new HttpClientInterceptorOptions().ThrowsOnMissingRegistration(); }
/// <summary> /// Registers a bundle of HTTP request interceptions from a specified JSON file. /// </summary> /// <param name="options">The <see cref="HttpClientInterceptorOptions"/> to register the bundle with.</param> /// <param name="path">The path of the JSON file containing the serialized bundle.</param> /// <returns> /// The value specified by <paramref name="options"/>. /// </returns> /// <exception cref="ArgumentNullException"> /// <paramref name="options"/> or <paramref name="path"/> is <see langword="null"/>. /// </exception> /// <exception cref="NotSupportedException"> /// The version of the serialized bundle is not supported. /// </exception> public static HttpClientInterceptorOptions RegisterBundle(this HttpClientInterceptorOptions options, string path) { return(options.RegisterBundle(path, Array.Empty <KeyValuePair <string, string> >())); }
/// <summary> /// Initializes a new instance of the <see cref="AuthenticationInterceptionBuilder"/> class. /// </summary> /// <param name="options">The <see cref="HttpClientInterceptorOptions"/> to use.</param> public AuthenticationInterceptionBuilder(HttpClientInterceptorOptions options) { Options = options; }
/// <summary> /// Registers one or more HTTP request interceptions, replacing any existing registrations. /// </summary> /// <param name="options">The <see cref="HttpClientInterceptorOptions"/> to set up.</param> /// <param name="collection">An array of one or more <see cref="HttpRequestInterceptionBuilder"/> instances to use to create the registration(s).</param> /// <returns> /// The current <see cref="HttpClientInterceptorOptions"/>. /// </returns> /// <exception cref="ArgumentNullException"> /// <paramref name="options"/> or <paramref name="collection"/> is <see langword="null"/>. /// </exception> public static HttpClientInterceptorOptions Register( this HttpClientInterceptorOptions options, params HttpRequestInterceptionBuilder[] collection) { return(options.Register((IEnumerable <HttpRequestInterceptionBuilder>)collection)); }
public async Task GetById_ValidRequest_ReturnsParsedResult() { // Arrange var options = new HttpClientInterceptorOptions(); new HttpRequestInterceptionBuilder() .Requests() .ForHttps() .ForHost("services.postcodeanywhere.co.uk") .ForPath("PostcodeAnywhere/Interactive/RetrieveById/v1.30/json3.ws") .IgnoringQuery() .Responds() .WithJsonContent(new { Items = new[] { new { Udprn = 5702847, Company = "", Department = "", Line1 = "4 Seagrave Road", Line2 = "", Line3 = "", Line4 = "", Line5 = "", PostTown = "Coventry", County = "West Midlands", Postcode = "CV1 2AA", Mailsort = 46111, Barcode = "(CV12AA1WM)", Type = "Residential", DeliveryPointSuffix = "1W", SubBuilding = "", BuildingName = "", BuildingNumber = "4", PrimaryStreet = "Seagrave Road", SecondaryStreet = "", DoubleDependentLocality = "", DependentLocality = "", PoBox = "", PrimaryStreetName = "Seagrave", PrimaryStreetType = "Road", SecondaryStreetName = "", SecondaryStreetType = "", CountryName = "England", CountryISO2 = "GB", CountryISO3 = "GBR" } } }) .RegisterWith(options); var httpClient = options.CreateHttpClient(); var service = new LoqateAddressSearchService(httpClient, new Options() { Key = "key" }); // Act var result = await service.GetById("123456.0"); // Assert Assert.NotNull(result); Assert.Equal("4 Seagrave Road", result.Line1); Assert.Equal("", result.Line2); Assert.Equal("", result.Line3); Assert.Equal("", result.Line4); Assert.Equal("Coventry", result.PostTown); Assert.Equal("West Midlands", result.County); Assert.Equal("CV1 2AA", result.Postcode); Assert.Equal("England", result.CountryName); }
/// <summary> /// Creates an <see cref="HttpClient"/> that uses the interceptors registered for the specified options and base address. /// </summary> /// <param name="options">The <see cref="HttpClientInterceptorOptions"/> to set up.</param> /// <param name="baseAddress">The base address to use for the created HTTP client.</param> /// <returns> /// The <see cref="HttpClient"/> that uses the specified <see cref="HttpClientInterceptorOptions"/>. /// </returns> /// <exception cref="ArgumentNullException"> /// <paramref name="options"/> is <see langword="null"/>. /// </exception> public static HttpClient CreateHttpClient(this HttpClientInterceptorOptions options, string baseAddress) { var baseAddressUri = new Uri(baseAddress, UriKind.RelativeOrAbsolute); return(options.CreateHttpClient(baseAddressUri)); }
/// <summary> /// Initializes a new instance of the <see cref="OpenIdTests{TOptions}"/> class. /// </summary> protected OpenIdTests() { Interceptor = new HttpClientInterceptorOptions() .ThrowsOnMissingRegistration() .RegisterBundle(Path.Combine(GetType().Name.Replace("Tests", string.Empty), "bundle.json")); }
/// <summary> /// Registers the builder with the specified <see cref="HttpClientInterceptorOptions"/> instance. /// </summary> /// <param name="builder">The <see cref="HttpRequestInterceptionBuilder"/> to use to create the registration.</param> /// <param name="options">The <see cref="HttpClientInterceptorOptions"/> to register the builder with.</param> /// <returns> /// The current <see cref="HttpRequestInterceptionBuilder"/>. /// </returns> /// <exception cref="ArgumentNullException"> /// <paramref name="builder"/> or <paramref name="options"/> is <see langword="null"/>. /// </exception> public static HttpRequestInterceptionBuilder RegisterWith(this HttpRequestInterceptionBuilder builder, HttpClientInterceptorOptions options) { if (options == null) { throw new ArgumentNullException(nameof(options)); } options.Register(builder); return(builder); }
internal HttpRequestInterceptionFilter(HttpClientInterceptorOptions options) { _options = options; }
public async Task SearchByPostcode_WithValidRequest_ReturnsParsedResults() { // Arrange var httpRequestInterceptor = new HttpClientInterceptorOptions(); new HttpRequestInterceptionBuilder() .Requests() .ForHttps() .ForHost("example.com") .ForPath("getaddress/XX2 00X") .ForQuery("api-key=key&expand=true&sort=true") .Responds() .WithJsonContent(new { postcode = "XX2 00X", latitude = 51.39020538330078, longitude = -0.1320359706878662, addresses = new[] { new { formatted_address = new[] { "658 Mitcham Road", "", "", "Croydon", "Surrey" }, thoroughfare = "Mitcham Road", building_name = "", sub_building_name = "", sub_building_number = "", building_number = "658", line_1 = "658 Mitcham Road", line_2 = "", line_3 = "", line_4 = "", locality = "", town_or_city = "Croydon", county = "Surrey", district = "Croydon", country = "England" }, new { formatted_address = new[] { "660 Mitcham Road", "", "", "Croydon", "Surrey" }, thoroughfare = "Mitcham Road", building_name = "", sub_building_name = "", sub_building_number = "", building_number = "660", line_1 = "660 Mitcham Road", line_2 = "", line_3 = "", line_4 = "", locality = "", town_or_city = "Croydon", county = "Surrey", district = "Croydon", country = "England" }, new { formatted_address = new[] { "Lanfranc School House", "Mitcham Road", "", "Croydon", "Surrey" }, thoroughfare = "Mitcham Road", building_name = "", sub_building_name = "Lanfranc School House", sub_building_number = "", building_number = "", line_1 = "Lanfranc School House", line_2 = "Mitcham Road", line_3 = "", line_4 = "", locality = "", town_or_city = "Croydon", county = "Surrey", district = "Croydon", country = "England" } } }) .RegisterWith(httpRequestInterceptor); var httpClient = httpRequestInterceptor.CreateHttpClient(); var options = new Mock <IOptions <GetAddressAddressSearchServiceOptions> >(); options.Setup(s => s.Value).Returns(new GetAddressAddressSearchServiceOptions { ApiUrl = "https://example.com/getaddress/{0}", ApiKey = "key" }); var service = new GetAddressAddressSearchService(httpClient, options.Object); // Act var result = await service.SearchByPostcode("XX2 00X"); // Assert Assert.Equal(3, result.Count); Assert.Equal($"XX2 00X::658 Mitcham Road", result.First().Id); Assert.Equal("658 Mitcham Road", result.First().StreetAddress); Assert.Equal("Croydon", result.First().Place); Assert.Equal($"XX2 00X::660 Mitcham Road", result.Skip(1).First().Id); Assert.Equal("660 Mitcham Road", result.Skip(1).First().StreetAddress); Assert.Equal("Croydon", result.Skip(1).First().Place); Assert.Equal($"XX2 00X::Lanfranc School House Mitcham Road", result.Skip(2).First().Id); Assert.Equal("Lanfranc School House Mitcham Road", result.Skip(2).First().StreetAddress); Assert.Equal("Croydon", result.Skip(2).First().Place); }