Search code examples
c#integration-testingwiremockminimal-apis

Can WireMock conditionally change authorization header for integration test?


I'm doing (learning about) integration testing on my web api. One of my web api methods calls out to EXTERNAL web service that takes Basic authorization.

So, I've intercepted my external web api call via WireMock with the following code in my WebApplicationFactory<> class:

services.AddHttpClient( 
    $"ExternalApiClient", 
    httpClient =>
    {
        httpClient.BaseAddress = new Uri( wireMockServer.Url );
        httpClient.DefaultRequestHeaders.Authorization = 
            new AuthenticationHeaderValue( 
                "Basic", 
                Convert.ToBase64String( Encoding.UTF8.GetBytes( "secret" ) ) 
            );
        httpClient.DefaultRequestHeaders.Add( "Accept", "*/*" );
    } 
);

With this, when I test my endpoint which requests its own HttpClient for the external service, it uses the WireMock server and serves up 'known' requests:

using var httpClient = httpClientFactory.CreateClient( "ExternalApiClient" );

So I would like to write two tests:

  1. Valid test where everything works.
  2. Invalid test where my Basic authentication password is wrong.

I can't think of a clean way to do this. Is there a WireMock (or integration test strategy) that would allow for this? I've written a WireMock pattern matcher to successfully do this, but I have to manually run one test or the other based on whether I've put the right password in my AddHttpClient call (I can't run all tests within the project with my solution).


Solution

  • My solution was as follows (if better options, please let me know):

    Since the credential 'management' is inside the API that WireMock is replacing, I didn't really see a way to simulate a 'real scenario' where simply the credentials were wrong. But all I really want to test is that my Api handles this error gracefully and returns expected result (a Api-Authorization-Failed header in the response).

    So I just introduced a fake url that WireMock would intercept and return 'invalid credential response' but in reality, the callers of my web api would never pass this url.

    server.Given(
        Request.Create()
            .WithPath( "/integration/unauthorized_api" )
            .UsingGet()
    ).RespondWith(
        Response.Create()
            .WithBody( @"{
            ""timestamp"": 1676572342225,
            ""status"": 401,
            ""error"": ""Unauthorized"",
            ""path"": ""{{request.path}}""
        }" )
            .WithHeader( "content-type", "application/json; charset=utf-8" )
            .WithStatusCode( HttpStatusCode.OK )
    );
    

    Then my [Fact] looks like this:

    [Fact]
    public async Task Get_ReturnsUnauthorized_WhenNexgenApiCredentialsAreWrong()
    {
        // Arrange
        var payload = GetValidRequest( "/integration/unauthorized_api", null );
        
        // Act
        var response = await httpClient.PostAsJsonAsync( "/nexgen", payload );
    
        // Assert 
        response.StatusCode.Should().Be( HttpStatusCode.Unauthorized );
        response.Headers.Single( h => h.Key == "Api-Authorization-Failed" ).Value.First().Should().Be( "true" );
    }