Can static mappings be used in xunit tests? #282

Closed
opened 2025-12-29 15:19:37 +01:00 by adam · 22 comments
Owner

Originally created by @jamoore5 on GitHub (Jun 30, 2020).

Can static mappings be used in xunit tests?

I tried creating a mapping under __admin/mappings in the test directory but the server does not seem to be finding the definitions.

Is it something that is supported?

Originally created by @jamoore5 on GitHub (Jun 30, 2020). Can static mappings be used in xunit tests? I tried creating a mapping under __admin/mappings in the test directory but the server does not seem to be finding the definitions. Is it something that is supported?
adam added the question label 2025-12-29 15:19:37 +01:00
adam closed this issue 2025-12-29 15:19:37 +01:00
Author
Owner

@StefH commented on GitHub (Jun 30, 2020):

Yes, this is possible.
I use the same logic:
https://github.com/WireMock-Net/WireMock.Net/tree/master/test/WireMock.Net.Tests/__admin/mappings

Note that CopyToOutputDirectory should be set correctly : https://github.com/WireMock-Net/WireMock.Net/blob/master/test/WireMock.Net.Tests/WireMock.Net.Tests.csproj#L89

And when running in XUnit, use the correct c# code to get the folder + files:
5e76a82a21/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithBodyFromFileTests.cs (L22)

@StefH commented on GitHub (Jun 30, 2020): Yes, this is possible. I use the same logic: https://github.com/WireMock-Net/WireMock.Net/tree/master/test/WireMock.Net.Tests/__admin/mappings Note that `CopyToOutputDirectory` should be set correctly : https://github.com/WireMock-Net/WireMock.Net/blob/master/test/WireMock.Net.Tests/WireMock.Net.Tests.csproj#L89 And when running in XUnit, use the correct c# code to get the folder + files: https://github.com/WireMock-Net/WireMock.Net/blob/5e76a82a219511ca5b54c9b7c62bb9217329458c/test/WireMock.Net.Tests/ResponseBuilders/ResponseWithBodyFromFileTests.cs#L22
Author
Owner

@jamoore5 commented on GitHub (Jul 1, 2020):

Thanks, @StefH that was very helpful.

I am seeing the mapping when the server starts, but none of them are matching the request. Any recommendations on how to debug why the mapping is not a match?

@jamoore5 commented on GitHub (Jul 1, 2020): Thanks, @StefH that was very helpful. I am seeing the mapping when the server starts, but none of them are matching the request. Any recommendations on how to debug why the mapping is not a match?
Author
Owner

@jamoore5 commented on GitHub (Jul 1, 2020):

Loging the request and the response

Request:
Method: POST, RequestUri: 'http://localhost:9095/interactionapi/SystemService.svc/User/search', Version: 1.1, Content: System.Net.Http.StringContent, Headers:
{
  Accept: application/json
  Content-Type: application/json; charset=utf-8
}
{"userSearchCriteria":{"IncludeInactive":true,"Id":"66"},"userReturnOptions":{"IncludeContact":true,"ContactReturnOptions":{"ElectronicAddressFlags":"PrimaryEmail"}}}

Response:
StatusCode: 404, ReasonPhrase: 'Not Found', Version: 1.1, Content: System.Net.Http.NoWriteNoSeekStreamContent, Headers:
{
  Date: Wed, 01 Jul 2020 00:35:14 GMT
  Server: Kestrel
  Transfer-Encoding: chunked
  Content-Type: application/json
}
{"Status":"No matching mapping found"}

the mapping

{
  "Guid": "bb4c0d1d-ef2e-4cd2-966a-850b8f1a2829",
  "Title": "Fetch_User_By_Id_66",
  "Request": {
    "Path": {
      "Matchers": [
        {
          "Name": "WildcardMatcher",
          "Pattern": "/interactionapi/SystemService.svc/User/search",
          "IgnoreCase": false
        }
      ]
    },
    "Methods": [
      "POST"
    ],
    "Body": {
      "Matcher": {
        "Name": "JsonMatcher",
        "Pattern": {
          "userSearchCriteria": {
            "IncludeInactive": true,
            "Id": "66"
          },
          "userReturnOptions": {
            "IncludeContact": true,
            "ContactReturnOptions": {
              "ElectronicAddressFlags": "PrimaryEmail"
            }
          }
        },
        "IgnoreCase": false
      }
    }
  },
  "Response": {
    "StatusCode": 200,
    "BodyAsJson": {
      "HttpStatusCode": 200,
      "InformationItems": [],
      "ErrorAdditionalText": "",
      "ErrorCode": 0,
      "ErrorFixSuggestion": "",
      "ErrorFixSupportContact": "",
      "ErrorParameters": null,
      "ErrorText": "",
      "RequestID": "494cc7fc-4de1-42cb-88bb-3c474b8b33df",
      "ResponseTime": 31,
      "HasNextPage": false,
      "TotalCount": 0,
      "Users": []
    },
    "Headers": {
      "Content-Type": "application/json",
      "Date": "Tue, 30 Jun 2020 22:32:19 GMT",
      "Server": "Apache",
      "Cache-Control": "no-cache",
      "X-LN-IA-API-TOTAL-TIME": "46.8494",
      "Persistent-Auth": "true",
      "X-Powered-By": "ASP.NET",
      "Vary": "Accept-Encoding"
    }
  }
}

I do not see why these are not matching?

@jamoore5 commented on GitHub (Jul 1, 2020): Loging the request and the response ``` Request: Method: POST, RequestUri: 'http://localhost:9095/interactionapi/SystemService.svc/User/search', Version: 1.1, Content: System.Net.Http.StringContent, Headers: { Accept: application/json Content-Type: application/json; charset=utf-8 } {"userSearchCriteria":{"IncludeInactive":true,"Id":"66"},"userReturnOptions":{"IncludeContact":true,"ContactReturnOptions":{"ElectronicAddressFlags":"PrimaryEmail"}}} Response: StatusCode: 404, ReasonPhrase: 'Not Found', Version: 1.1, Content: System.Net.Http.NoWriteNoSeekStreamContent, Headers: { Date: Wed, 01 Jul 2020 00:35:14 GMT Server: Kestrel Transfer-Encoding: chunked Content-Type: application/json } {"Status":"No matching mapping found"} ``` the mapping ``` js { "Guid": "bb4c0d1d-ef2e-4cd2-966a-850b8f1a2829", "Title": "Fetch_User_By_Id_66", "Request": { "Path": { "Matchers": [ { "Name": "WildcardMatcher", "Pattern": "/interactionapi/SystemService.svc/User/search", "IgnoreCase": false } ] }, "Methods": [ "POST" ], "Body": { "Matcher": { "Name": "JsonMatcher", "Pattern": { "userSearchCriteria": { "IncludeInactive": true, "Id": "66" }, "userReturnOptions": { "IncludeContact": true, "ContactReturnOptions": { "ElectronicAddressFlags": "PrimaryEmail" } } }, "IgnoreCase": false } } }, "Response": { "StatusCode": 200, "BodyAsJson": { "HttpStatusCode": 200, "InformationItems": [], "ErrorAdditionalText": "", "ErrorCode": 0, "ErrorFixSuggestion": "", "ErrorFixSupportContact": "", "ErrorParameters": null, "ErrorText": "", "RequestID": "494cc7fc-4de1-42cb-88bb-3c474b8b33df", "ResponseTime": 31, "HasNextPage": false, "TotalCount": 0, "Users": [] }, "Headers": { "Content-Type": "application/json", "Date": "Tue, 30 Jun 2020 22:32:19 GMT", "Server": "Apache", "Cache-Control": "no-cache", "X-LN-IA-API-TOTAL-TIME": "46.8494", "Persistent-Auth": "true", "X-Powered-By": "ASP.NET", "Vary": "Accept-Encoding" } } } ``` I do not see why these are not matching?
Author
Owner

@StefH commented on GitHub (Jul 1, 2020):

When using postman, it works fine?
image

@StefH commented on GitHub (Jul 1, 2020): When using postman, it works fine? ![image](https://user-images.githubusercontent.com/249938/86217337-a0b9e700-bb7f-11ea-848b-15ea7f9c4d47.png)
Author
Owner

@jamoore5 commented on GitHub (Jul 1, 2020):

Yes it seem to work fine when I call it through the code with a standalone server, it is only failing when it is setup in the unit test. I tested the same call and mapping with a stand-alone server and it passes. I confirmed that the static mapping is loaded in the test, it just does not match.

Very confused.

@jamoore5 commented on GitHub (Jul 1, 2020): Yes it seem to work fine when I call it through the code with a standalone server, it is only failing when it is setup in the unit test. I tested the same call and mapping with a stand-alone server and it passes. I confirmed that the static mapping is loaded in the test, it just does not match. Very confused.
Author
Owner

@StefH commented on GitHub (Jul 1, 2020):

https://github.com/WireMock-Net/WireMock.Net/pull/482

@StefH commented on GitHub (Jul 1, 2020): https://github.com/WireMock-Net/WireMock.Net/pull/482
Author
Owner

@StefH commented on GitHub (Jul 1, 2020):

I've created a new preview version (NuGet : WireMock.Net.1.2.13-ci-13536) --> https://github.com/WireMock-Net/WireMock.Net/wiki/MyGet-preview-versions

This one includes in the LogEntry a Partial which shows which things can match or don't match.
--> https://github.com/WireMock-Net/WireMock.Net/blob/master/src/WireMock.Net/Server/WireMockServer.LogEntries.cs#L42

@StefH commented on GitHub (Jul 1, 2020): I've created a new preview version (NuGet : WireMock.Net.1.2.13-ci-13536) --> https://github.com/WireMock-Net/WireMock.Net/wiki/MyGet-preview-versions This one includes in the LogEntry a Partial which shows which things can match or don't match. --> https://github.com/WireMock-Net/WireMock.Net/blob/master/src/WireMock.Net/Server/WireMockServer.LogEntries.cs#L42
Author
Owner

@StefH commented on GitHub (Jul 4, 2020):

@jamoore5
See this wiki page to help you finding your matching issue when you use the specified preview version.

(https://github.com/WireMock-Net/WireMock.Net/wiki/Request-Matching-Tips)

@StefH commented on GitHub (Jul 4, 2020): @jamoore5 See this wiki page to help you finding your matching issue when you use the specified preview version. (https://github.com/WireMock-Net/WireMock.Net/wiki/Request-Matching-Tips)
Author
Owner

@jamoore5 commented on GitHub (Jul 8, 2020):

Thank, the directions were very helpful. The problem looks to be that the body is not being included in the WireMock.RequestMessage. I added a logger to the HttpClient handler and do see the body is being passed.

{
  Accept: application/json
  Content-Type: application/json; charset=utf-8
}
{"userSearchCriteria":{"IncludeInactive":true,"Id":"66"},"userReturnOptions":{"IncludeContact":true,"ContactReturnOptions":{"ElectronicAddressFlags":"PrimaryEmail"}}}

Response:
StatusCode: 404, ReasonPhrase: 'Not Found', Version: 1.1, Content: System.Net.Http.NoWriteNoSeekStreamContent, Headers:
{
  Date: Wed, 08 Jul 2020 16:10:32 GMT
  Server: Kestrel
  Transfer-Encoding: chunked
  Content-Type: application/json
}
{"Status":"No matching mapping found"}

Is there an easy way to print the LogEntry to console?

@jamoore5 commented on GitHub (Jul 8, 2020): Thank, the directions were very helpful. The problem looks to be that the body is not being included in the `WireMock.RequestMessage`. I added a logger to the HttpClient handler and do see the body is being passed. ```Method: POST, RequestUri: 'http://localhost:9095/interactionapi/SystemService.svc/User/search', Version: 1.1, Content: System.Net.Http.StringContent, Headers: { Accept: application/json Content-Type: application/json; charset=utf-8 } {"userSearchCriteria":{"IncludeInactive":true,"Id":"66"},"userReturnOptions":{"IncludeContact":true,"ContactReturnOptions":{"ElectronicAddressFlags":"PrimaryEmail"}}} Response: StatusCode: 404, ReasonPhrase: 'Not Found', Version: 1.1, Content: System.Net.Http.NoWriteNoSeekStreamContent, Headers: { Date: Wed, 08 Jul 2020 16:10:32 GMT Server: Kestrel Transfer-Encoding: chunked Content-Type: application/json } {"Status":"No matching mapping found"} ``` Is there an easy way to print the LogEntry to console?
Author
Owner

@jamoore5 commented on GitHub (Jul 8, 2020):

Screen Shot 2020-07-08 at 1 14 05 PM
@jamoore5 commented on GitHub (Jul 8, 2020): <img width="1009" alt="Screen Shot 2020-07-08 at 1 14 05 PM" src="https://user-images.githubusercontent.com/14077644/86943584-01679780-c11d-11ea-824a-280657bb3e24.png">
Author
Owner

@StefH commented on GitHub (Jul 8, 2020):

Can you post your full unit test code?

@StefH commented on GitHub (Jul 8, 2020): Can you post your full unit test code?
Author
Owner

@jamoore5 commented on GitHub (Jul 8, 2020):

using System;
using System.Net;
using System.Net.Http;
using System.Reflection;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Threading.Tasks;
using Xunit;

namespace Toolkit.Adapter.InteractionClient.Tests
{
    public class EntityControllerTestsGetEntityAsync : ControllerTestBase
    {
        [Fact]
        public async Task FetchUserThatExist_ReturnEntity()
        {
            // Act
            var response = await Client.GetAsync("/api/v1.0/entities/6/User/2");

            // Assert
            var entity = (UserEntity) await AssertSuccessResponse(response, typeof(UserEntity));

            Assert.Contains("/api/v1.0/entities/6/User/2", entity.EntityKey);
            Assert.EndsWith("/User", entity.Schema);
            Assert.Contains( "/api/v1.0/schema/6/", entity.Schema);
            Assert.Contains("/api/v1.0/entities/6/User/2", entity.Attributes.Id);
            Assert.Contains("/api/v1.0/entities/6/Contact/F2i13", entity.Attributes.FirmContactId);
            Assert.Equal("Julie Ann", entity.Attributes.FirstName);
            Assert.Equal("Moore", entity.Attributes.LastName);
            Assert.Equal("julieanne.moore@introhive.com", entity.Attributes.EmailAddress);
            Assert.True(entity.Attributes.IsActive);
        }

        public static string[] GetEmbeddedResourceNames()
        {
            return Assembly.GetExecutingAssembly().GetManifestResourceNames();
        }

        [Fact]
        public async Task FetchUserThatDoesNotExist_ReturnNotFound()
        {
            // Act
            var response = await Client.GetAsync("/api/v1.0/entities/6/User/66");

            // Assert
            await AssertNotFoundResponse(response);
        }

        [Fact]
        public async Task FetchEntityDoesNotExist_ReturnBadRequest()
        {
            // Act
            var response = await Client.GetAsync("/api/v1.0/entities/6/Random/2");

            // Assert
            await AssertBadRequestResponse(response);
        }

        private async Task<IEntity> AssertSuccessResponse(HttpResponseMessage response, Type entityType)
        {
            Assert.True(response.IsSuccessStatusCode, await response.Content.ReadAsStringAsync());
            Assert.NotNull(response.Content.Headers.ContentType);
            Assert.Equal("application/json", response.Content.Headers.ContentType.MediaType);

            var json = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
            Assert.True(json.RootElement.TryGetProperty("data", out var data));

            Assert.True(data.TryGetProperty("entities", out var entities));
            Assert.Equal(1, entities.GetArrayLength());

            return (IEntity) JsonSerializer.Deserialize(entities[0].GetRawText(), entityType, new JsonSerializerOptions());
        }

        private async Task AssertNotFoundResponse(HttpResponseMessage response)
        {
            // Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
            Assert.NotNull(response.Content.Headers.ContentType);
            Assert.Equal("application/json", response.Content.Headers.ContentType.MediaType);

            var json = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
            Assert.True(json.RootElement.TryGetProperty("errors", out var errors));
            Assert.Equal(1, errors.GetArrayLength());

            var error = JsonSerializer.Deserialize<ErrorResponse>(errors[0].GetRawText(), new JsonSerializerOptions());
            Assert.NotNull(error.Id);
            Assert.Equal("No records found.", error.Title);
            Assert.Equal("NotFound (404)", error.Status);
            Assert.Equal("CE1002", error.Code);
            Assert.NotNull(error.Detail);
        }

        private async Task AssertBadRequestResponse(HttpResponseMessage response)
        {
            Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode);
            Assert.NotNull(response.Content.Headers.ContentType);
            Assert.Equal("application/json", response.Content.Headers.ContentType.MediaType);

            var json = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
            Assert.True(json.RootElement.TryGetProperty("errors", out var errors));
            Assert.Equal(1, errors.GetArrayLength());

            var error = JsonSerializer.Deserialize<ErrorResponse>(errors[0].GetRawText(), new JsonSerializerOptions());
            Assert.NotNull(error.Id);
            Assert.Equal("BadRequest (400)", error.Status);
            Assert.Equal("RE1002", error.Code);
            Assert.Equal("Adapter request error. Invalid entity type in request.", error.Title);
            Assert.NotNull(error.Detail);
        }
    }

    class ErrorResponse
    {
        public string Id { get; set; }
        public string Status { get; set; }
        public string Code { get; set; }
        public string Title { get; set; }
        public string Detail { get; set; }
    }

    interface IEntity
    {

    }

    class UserEntity : IEntity
    {
        [JsonPropertyName("entityKey")]
        public string EntityKey { get; set; }
        [JsonPropertyName("schema")]
        public string Schema { get; set; }
        [JsonPropertyName("attributes")]
        public UserAttributes Attributes { get; set; }
    }

    class UserAttributes
    {
        public string Id { get; set; }
        public string FirmContactId { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string EmailAddress { get; set; }
        public bool IsActive { get; set; }
    }
}
using System;
using System.IO;
using System.Net.Http;
using System.Net.Http.Headers;
using Microsoft.AspNetCore.Mvc.Testing;
using WireMock.Server;
using WireMock.Settings;

namespace Toolkit.Adapter.InteractionClient.Tests
{
    public class ControllerTestBase : IDisposable
    {
        private readonly WebApplicationFactory<Startup> _factory;
        protected HttpClient Client { get; }

        protected WireMockServer Server { get; set; }

        protected ControllerTestBase()
        {
            _factory = new WebApplicationFactory<Startup>();

            // Create an HttpClient which is setup for the test host
            Client = _factory.CreateClient();

            StartMockServer();
        }


        public void StartMockServer()
        {
            var settings = new WireMockServerSettings
            {
                Urls = new[] { "http://localhost:9095" },
                // AllowPartialMapping = true,
                // Logger = new WireMockConsoleLogger(),
                // ProxyAndRecordSettings = new ProxyAndRecordSettings
                // {
                //     Url = "https://cmapp02.cmdom.co.uk",
                //     SaveMapping = true,
                //     SaveMappingToFile = true,
                //     BlackListedHeaders = new [] { "Authorization", "Request-Id" },
                //     SaveMappingForStatusCodePattern = "2xx"
                // }
            };

            Server = WireMockServer.Start(settings);
            var path = Path.Combine(Directory.GetCurrentDirectory(), "__admin", "mappings");
            Server.ReadStaticMappings(path);
        }

        public void Dispose()
        {
            _factory.Dispose();
            Server.Stop();
            Client.Dispose();
        }
    }
}

Sorry code is in a privarte repo, so I cannot just share the branch. I will see if I can simply the test without the production code and still reproduce the error I am seeing.

Edit so far when I smipfy it to just make an http call it works. going to have to make a mock project to call to see if the calling through WebApplicationFactory is the problem.

@jamoore5 commented on GitHub (Jul 8, 2020): ``` c# using System; using System.Net; using System.Net.Http; using System.Reflection; using System.Text.Json; using System.Text.Json.Serialization; using System.Threading.Tasks; using Xunit; namespace Toolkit.Adapter.InteractionClient.Tests { public class EntityControllerTestsGetEntityAsync : ControllerTestBase { [Fact] public async Task FetchUserThatExist_ReturnEntity() { // Act var response = await Client.GetAsync("/api/v1.0/entities/6/User/2"); // Assert var entity = (UserEntity) await AssertSuccessResponse(response, typeof(UserEntity)); Assert.Contains("/api/v1.0/entities/6/User/2", entity.EntityKey); Assert.EndsWith("/User", entity.Schema); Assert.Contains( "/api/v1.0/schema/6/", entity.Schema); Assert.Contains("/api/v1.0/entities/6/User/2", entity.Attributes.Id); Assert.Contains("/api/v1.0/entities/6/Contact/F2i13", entity.Attributes.FirmContactId); Assert.Equal("Julie Ann", entity.Attributes.FirstName); Assert.Equal("Moore", entity.Attributes.LastName); Assert.Equal("julieanne.moore@introhive.com", entity.Attributes.EmailAddress); Assert.True(entity.Attributes.IsActive); } public static string[] GetEmbeddedResourceNames() { return Assembly.GetExecutingAssembly().GetManifestResourceNames(); } [Fact] public async Task FetchUserThatDoesNotExist_ReturnNotFound() { // Act var response = await Client.GetAsync("/api/v1.0/entities/6/User/66"); // Assert await AssertNotFoundResponse(response); } [Fact] public async Task FetchEntityDoesNotExist_ReturnBadRequest() { // Act var response = await Client.GetAsync("/api/v1.0/entities/6/Random/2"); // Assert await AssertBadRequestResponse(response); } private async Task<IEntity> AssertSuccessResponse(HttpResponseMessage response, Type entityType) { Assert.True(response.IsSuccessStatusCode, await response.Content.ReadAsStringAsync()); Assert.NotNull(response.Content.Headers.ContentType); Assert.Equal("application/json", response.Content.Headers.ContentType.MediaType); var json = JsonDocument.Parse(await response.Content.ReadAsStringAsync()); Assert.True(json.RootElement.TryGetProperty("data", out var data)); Assert.True(data.TryGetProperty("entities", out var entities)); Assert.Equal(1, entities.GetArrayLength()); return (IEntity) JsonSerializer.Deserialize(entities[0].GetRawText(), entityType, new JsonSerializerOptions()); } private async Task AssertNotFoundResponse(HttpResponseMessage response) { // Assert.Equal(HttpStatusCode.NotFound, response.StatusCode); Assert.NotNull(response.Content.Headers.ContentType); Assert.Equal("application/json", response.Content.Headers.ContentType.MediaType); var json = JsonDocument.Parse(await response.Content.ReadAsStringAsync()); Assert.True(json.RootElement.TryGetProperty("errors", out var errors)); Assert.Equal(1, errors.GetArrayLength()); var error = JsonSerializer.Deserialize<ErrorResponse>(errors[0].GetRawText(), new JsonSerializerOptions()); Assert.NotNull(error.Id); Assert.Equal("No records found.", error.Title); Assert.Equal("NotFound (404)", error.Status); Assert.Equal("CE1002", error.Code); Assert.NotNull(error.Detail); } private async Task AssertBadRequestResponse(HttpResponseMessage response) { Assert.Equal(HttpStatusCode.BadRequest, response.StatusCode); Assert.NotNull(response.Content.Headers.ContentType); Assert.Equal("application/json", response.Content.Headers.ContentType.MediaType); var json = JsonDocument.Parse(await response.Content.ReadAsStringAsync()); Assert.True(json.RootElement.TryGetProperty("errors", out var errors)); Assert.Equal(1, errors.GetArrayLength()); var error = JsonSerializer.Deserialize<ErrorResponse>(errors[0].GetRawText(), new JsonSerializerOptions()); Assert.NotNull(error.Id); Assert.Equal("BadRequest (400)", error.Status); Assert.Equal("RE1002", error.Code); Assert.Equal("Adapter request error. Invalid entity type in request.", error.Title); Assert.NotNull(error.Detail); } } class ErrorResponse { public string Id { get; set; } public string Status { get; set; } public string Code { get; set; } public string Title { get; set; } public string Detail { get; set; } } interface IEntity { } class UserEntity : IEntity { [JsonPropertyName("entityKey")] public string EntityKey { get; set; } [JsonPropertyName("schema")] public string Schema { get; set; } [JsonPropertyName("attributes")] public UserAttributes Attributes { get; set; } } class UserAttributes { public string Id { get; set; } public string FirmContactId { get; set; } public string FirstName { get; set; } public string LastName { get; set; } public string EmailAddress { get; set; } public bool IsActive { get; set; } } } ``` ``` c# using System; using System.IO; using System.Net.Http; using System.Net.Http.Headers; using Microsoft.AspNetCore.Mvc.Testing; using WireMock.Server; using WireMock.Settings; namespace Toolkit.Adapter.InteractionClient.Tests { public class ControllerTestBase : IDisposable { private readonly WebApplicationFactory<Startup> _factory; protected HttpClient Client { get; } protected WireMockServer Server { get; set; } protected ControllerTestBase() { _factory = new WebApplicationFactory<Startup>(); // Create an HttpClient which is setup for the test host Client = _factory.CreateClient(); StartMockServer(); } public void StartMockServer() { var settings = new WireMockServerSettings { Urls = new[] { "http://localhost:9095" }, // AllowPartialMapping = true, // Logger = new WireMockConsoleLogger(), // ProxyAndRecordSettings = new ProxyAndRecordSettings // { // Url = "https://cmapp02.cmdom.co.uk", // SaveMapping = true, // SaveMappingToFile = true, // BlackListedHeaders = new [] { "Authorization", "Request-Id" }, // SaveMappingForStatusCodePattern = "2xx" // } }; Server = WireMockServer.Start(settings); var path = Path.Combine(Directory.GetCurrentDirectory(), "__admin", "mappings"); Server.ReadStaticMappings(path); } public void Dispose() { _factory.Dispose(); Server.Stop(); Client.Dispose(); } } } ``` Sorry code is in a privarte repo, so I cannot just share the branch. I will see if I can simply the test without the production code and still reproduce the error I am seeing. Edit so far when I smipfy it to just make an http call it works. going to have to make a mock project to call to see if the calling through WebApplicationFactory is the problem.
Author
Owner

@StefH commented on GitHub (Jul 8, 2020):

Can you please post the c# code for "Fetch_User_By_Id_66" ? Because that's the one which gives issues.

And indeed, just use new HttpClient() instead of the WebApplicationFactory.

@StefH commented on GitHub (Jul 8, 2020): Can you please post the c# code for "Fetch_User_By_Id_66" ? Because that's the one which gives issues. And indeed, just use `new HttpClient()` instead of the WebApplicationFactory.
Author
Owner

@jamoore5 commented on GitHub (Jul 8, 2020):

I
am trying to integration test my applications api that makes external calls to another api. That is why I am using WebApplicationFactory.

Maybe it is the wrong approach to integration tests?

_factory = new WebApplicationFactory<Startup>();

// Create an HttpClient which is setup for the test host
Client = _factory.CreateClient();

await Client.GetAsync("/api/v1.0/entities/6/User/2"); call my web app, which then makes an external call to the mock server.

It works when I make the direct call to the webserver but does not work when I make the indirect call through my api.

I will try to make a mock project and see if I can reproduce the issue.

@jamoore5 commented on GitHub (Jul 8, 2020): I am trying to integration test my applications api that makes external calls to another api. That is why I am using WebApplicationFactory. Maybe it is the wrong approach to integration tests? ``` _factory = new WebApplicationFactory<Startup>(); // Create an HttpClient which is setup for the test host Client = _factory.CreateClient(); ``` `await Client.GetAsync("/api/v1.0/entities/6/User/2");` call my web app, which then makes an external call to the mock server. It works when I make the direct call to the webserver but does not work when I make the indirect call through my api. I will try to make a mock project and see if I can reproduce the issue.
Author
Owner

@StefH commented on GitHub (Jul 8, 2020):

You want to test a client --> web app --> external API = WireMock

Are you sure the web-app does a POST request to /interactionapi/SystemService.svc/User/search ?

And how does BodyData look?
image

@StefH commented on GitHub (Jul 8, 2020): You want to test `a client --> web app --> external API = WireMock` Are you sure the web-app does a POST request to /interactionapi/SystemService.svc/User/search ? And how does **BodyData** look? ![image](https://user-images.githubusercontent.com/249938/86959213-b28e2200-c15d-11ea-8423-55f4364ad210.png)
Author
Owner

@jamoore5 commented on GitHub (Jul 8, 2020):

I added this handler on the HttpClient

public class LoggingHandler : DelegatingHandler
    {
        public LoggingHandler(HttpMessageHandler innerHandler)
            : base(innerHandler)
        {
        }

        protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
            CancellationToken cancellationToken)
        {
            Console.WriteLine("Request:");
            Console.WriteLine(request.ToString());
            if (request.Content != null)
            {
                Console.WriteLine(await request.Content.ReadAsStringAsync());
            }

            Console.WriteLine();

            HttpResponseMessage response = await base.SendAsync(request, cancellationToken);

            Console.WriteLine("Response:");
            Console.WriteLine(response.ToString());
            if (response.Content != null)
            {
                Console.WriteLine(await response.Content.ReadAsStringAsync());
            }

            Console.WriteLine();

            return response;
        }
    }

and it is outputing

A total of 1 test files matched the specified pattern.
Hosting environment: Production
Content root path: /Users/jamoore/Development/integration_toolkit/Tests/Toolkit.Adapter.InteractionClient.Tests/bin/Interaction/netcoreapp3.1/
Now listening on: http://0.0.0.0:9095
Request:
Method: POST, RequestUri: 'http://localhost:9095/interactionapi/SystemService.svc/User/search', Version: 1.1, Content: System.Net.Http.StringContent, Headers:
{
  Accept: application/json
  Content-Type: application/json; charset=utf-8
}
{"userSearchCriteria":{"IncludeInactive":true,"Id":"66"},"userReturnOptions":{"IncludeContact":true,"ContactReturnOptions":{"ElectronicAddressFlags":"PrimaryEmail"}}}

Response:
StatusCode: 404, ReasonPhrase: 'Not Found', Version: 1.1, Content: System.Net.Http.NoWriteNoSeekStreamContent, Headers:
{
  Date: Wed, 08 Jul 2020 16:10:32 GMT
  Server: Kestrel
  Transfer-Encoding: chunked
  Content-Type: application/json
}
{"Status":"No matching mapping found"}

So I am confident that there is a body and some bug is causing the mock server not to see it.

But so far I cannot simplify the code and still reproduce the error. However I am still trying to make a simpler project that reproduces the bug.

@jamoore5 commented on GitHub (Jul 8, 2020): I added this handler on the HttpClient ``` public class LoggingHandler : DelegatingHandler { public LoggingHandler(HttpMessageHandler innerHandler) : base(innerHandler) { } protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { Console.WriteLine("Request:"); Console.WriteLine(request.ToString()); if (request.Content != null) { Console.WriteLine(await request.Content.ReadAsStringAsync()); } Console.WriteLine(); HttpResponseMessage response = await base.SendAsync(request, cancellationToken); Console.WriteLine("Response:"); Console.WriteLine(response.ToString()); if (response.Content != null) { Console.WriteLine(await response.Content.ReadAsStringAsync()); } Console.WriteLine(); return response; } } ``` and it is outputing ``` A total of 1 test files matched the specified pattern. Hosting environment: Production Content root path: /Users/jamoore/Development/integration_toolkit/Tests/Toolkit.Adapter.InteractionClient.Tests/bin/Interaction/netcoreapp3.1/ Now listening on: http://0.0.0.0:9095 Request: Method: POST, RequestUri: 'http://localhost:9095/interactionapi/SystemService.svc/User/search', Version: 1.1, Content: System.Net.Http.StringContent, Headers: { Accept: application/json Content-Type: application/json; charset=utf-8 } {"userSearchCriteria":{"IncludeInactive":true,"Id":"66"},"userReturnOptions":{"IncludeContact":true,"ContactReturnOptions":{"ElectronicAddressFlags":"PrimaryEmail"}}} Response: StatusCode: 404, ReasonPhrase: 'Not Found', Version: 1.1, Content: System.Net.Http.NoWriteNoSeekStreamContent, Headers: { Date: Wed, 08 Jul 2020 16:10:32 GMT Server: Kestrel Transfer-Encoding: chunked Content-Type: application/json } {"Status":"No matching mapping found"} ``` So I am confident that there is a body and some bug is causing the mock server not to see it. But so far I cannot simplify the code and still reproduce the error. However I am still trying to make a simpler project that reproduces the bug.
Author
Owner

@jamoore5 commented on GitHub (Jul 8, 2020):

I finally reproduced the issue

using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Xunit;

namespace DummyWebApplication.Tests
{
    public class UnitTest1 : ControllerTestBase
    {
        [Fact]
        public async Task Test2()
        {
            AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false);
            var uri = new Uri("http://localhost:9095/interactionapi/");
            var credentials = new CredentialCache
            {
                {
                    uri, "NTLM",
                    new NetworkCredential("username",
                        "password",
                        "domain")
                }
            };
            var handler = new HttpClientHandler {Credentials = credentials};
            var client = new HttpClient(handler);

            var response = SendRequestAsync(
                    client,
                    "http://localhost:9095/interactionapi/SystemService.svc/User/search",
                    "{\"userSearchCriteria\":{\"IncludeInactive\":true,\"Id\":\"66\"},\"userReturnOptions\":{\"IncludeContact\":true,\"ContactReturnOptions\":{\"ElectronicAddressFlags\":\"PrimaryEmail\"}}}",
                    HttpMethod.Post).Result;


            Assert.True(response.IsSuccessStatusCode, await response.Content.ReadAsStringAsync());
        }

        private async Task<HttpResponseMessage> SendRequestAsync(HttpClient client, string endpoint, string contentBody,
            HttpMethod method, Dictionary<string, string> headers = null)
        {
            var httpRequestMessage = BuildRequestMessage(endpoint, contentBody, method, headers);
            return await SendRequestAsync(client, httpRequestMessage);
        }

        private HttpRequestMessage BuildRequestMessage(string endpoint, string contentBody, HttpMethod action, Dictionary<string, string> headers)
        {
            var uri = new Uri(endpoint);

            var httpRequestMessage = new HttpRequestMessage
            {
                Method = action,
                RequestUri = uri,
                Content = BuildContentBody(contentBody)
            };

            return httpRequestMessage;
        }

        private static StringContent BuildContentBody(string contentBody)
        {
            return new StringContent(contentBody, Encoding.UTF8, "application/json");
        }

        private async Task<HttpResponseMessage> SendRequestAsync(HttpClient client, HttpRequestMessage httpRequestMessage)
        {
            var responseMessage = await client.SendAsync(httpRequestMessage);

            return responseMessage;

        }
    }
}

The cause of the problem AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false);

If you comment tnat line out the test passes.

Link to sample solution

Is this a bug in the plugin?

@jamoore5 commented on GitHub (Jul 8, 2020): I finally reproduced the issue ``` c# using System; using System.Collections.Generic; using System.Net; using System.Net.Http; using System.Text; using System.Threading.Tasks; using Xunit; namespace DummyWebApplication.Tests { public class UnitTest1 : ControllerTestBase { [Fact] public async Task Test2() { AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false); var uri = new Uri("http://localhost:9095/interactionapi/"); var credentials = new CredentialCache { { uri, "NTLM", new NetworkCredential("username", "password", "domain") } }; var handler = new HttpClientHandler {Credentials = credentials}; var client = new HttpClient(handler); var response = SendRequestAsync( client, "http://localhost:9095/interactionapi/SystemService.svc/User/search", "{\"userSearchCriteria\":{\"IncludeInactive\":true,\"Id\":\"66\"},\"userReturnOptions\":{\"IncludeContact\":true,\"ContactReturnOptions\":{\"ElectronicAddressFlags\":\"PrimaryEmail\"}}}", HttpMethod.Post).Result; Assert.True(response.IsSuccessStatusCode, await response.Content.ReadAsStringAsync()); } private async Task<HttpResponseMessage> SendRequestAsync(HttpClient client, string endpoint, string contentBody, HttpMethod method, Dictionary<string, string> headers = null) { var httpRequestMessage = BuildRequestMessage(endpoint, contentBody, method, headers); return await SendRequestAsync(client, httpRequestMessage); } private HttpRequestMessage BuildRequestMessage(string endpoint, string contentBody, HttpMethod action, Dictionary<string, string> headers) { var uri = new Uri(endpoint); var httpRequestMessage = new HttpRequestMessage { Method = action, RequestUri = uri, Content = BuildContentBody(contentBody) }; return httpRequestMessage; } private static StringContent BuildContentBody(string contentBody) { return new StringContent(contentBody, Encoding.UTF8, "application/json"); } private async Task<HttpResponseMessage> SendRequestAsync(HttpClient client, HttpRequestMessage httpRequestMessage) { var responseMessage = await client.SendAsync(httpRequestMessage); return responseMessage; } } } ``` The cause of the problem `AppContext.SetSwitch("System.Net.Http.UseSocketsHttpHandler", false);` If you comment tnat line out the test passes. [Link to sample solution ](https://github.com/jamoore5/WireMockTest) Is this a bug in the plugin?
Author
Owner

@StefH commented on GitHub (Jul 9, 2020):

  1. Do you use windows operating system for running the tests + WireMock?

  2. I guess you already have read this page ? --> https://docs.microsoft.com/en-us/dotnet/core/run-time-config/networking

@StefH commented on GitHub (Jul 9, 2020): 1. Do you use windows operating system for running the tests + WireMock? 2. I guess you already have read this page ? --> https://docs.microsoft.com/en-us/dotnet/core/run-time-config/networking
Author
Owner

@jamoore5 commented on GitHub (Jul 9, 2020):

1. Do you use windows operating system for running the tests + WireMock?

MacOS

2. I guess you already have read this page ? --> https://docs.microsoft.com/en-us/dotnet/core/run-time-config/networking

it seems that we need to turn off SocketsHttpHandler because

Apparently normally it will try Kerberos auth first and if that fails it will fall back to ntlm, but we're just sending a single request and dotnet has an issue where we can't tell it to try ntlm first so we just don't let it try Kerebos at all.

@jamoore5 commented on GitHub (Jul 9, 2020): > 1. Do you use windows operating system for running the tests + WireMock? MacOS > 2. I guess you already have read this page ? --> https://docs.microsoft.com/en-us/dotnet/core/run-time-config/networking it seems that we need to turn off SocketsHttpHandler because > Apparently normally it will try Kerberos auth first and if that fails it will fall back to ntlm, but we're just sending a single request and dotnet has an issue where we can't tell it to try ntlm first so we just don't let it try Kerebos at all.
Author
Owner

@StefH commented on GitHub (Jul 11, 2020):

Can this issue be closed?

@StefH commented on GitHub (Jul 11, 2020): Can this issue be closed?
Author
Owner

@jamoore5 commented on GitHub (Jul 13, 2020):

I figured out the cause of the issue, but am not sure what to do to fix that mapping do not with my project. I guess if the configuration we are using is not supported, this can be closed.

@jamoore5 commented on GitHub (Jul 13, 2020): I figured out the cause of the issue, but am not sure what to do to fix that mapping do not with my project. I guess if the configuration we are using is not supported, this can be closed.
Author
Owner

@StefH commented on GitHub (Jul 13, 2020):

Yes sorry, it seems that using the SocketsHttpHandler as you do is not supported by WireMock.Net

So I will close this issue now.

@StefH commented on GitHub (Jul 13, 2020): Yes sorry, it seems that using the `SocketsHttpHandler` as you do is not supported by WireMock.Net So I will close this issue now.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/WireMock.Net-wiremock#282