How to Integrate Testing a Controller, which inside that controller, methods gets token from another site

Viewed 90

I'm setting up an API which it gets authenticated to another server through JWT. one of Controller's methods I want to test, gets the token from an external site. how can I test this method?

I made a Test server and tried to mimic the website action which providing tokens.i can access this Test Server through Test Methods but I can't get to it from the actual controller.

here is my Test Server setup method MockedController is the Controller supposed to provide toke and is working fine and I can get tokens from test units. AuthController is the Controller supposed to test.

var server = new TestServer(
                new WebHostBuilder()
                .UseEnvironment(TestConstants.EnvironmentName)
                .UseStartup<Startup>()
                .UseUrls(TestConstants.MockAddress)
                .ConfigureTestServices(config =>
                {
                    config.AddOptions();
                    config.AddMvc()
                       .SetCompatibilityVersion(Microsoft.AspNetCore.Mvc.CompatibilityVersion.Version_2_2)
                        .AddApplicationPart(typeof(AuthController).Assembly)
                        .AddApplicationPart(typeof(MockedTokenController).Assembly)
                        ;

                    config.AddSingleton<MockedTokenController>();
                    config.BuildServiceProvider();
                }));
            server.BaseAddress = new Uri(TestConstants.MockAddress);
            server.CreateHandler();
            _client = server.CreateClient();
            _client.BaseAddress = new Uri(TestConstants.MockAddress);// I tried with and without this line

Here is the test method which is failing

 var request = new HttpRequestMessage(HttpMethod.Get, "/Auth/Login");
            var response = await _client.SendAsync(request);
            var contents = await response.Content.ReadAsStringAsync();
            Assert.Equal(HttpStatusCode.OK, response.StatusCode);

Here is the AuthController Login Method code

[HttpGet("Login")]
public async Task<IActionResult> LoginAsync(){
         var token = await _authService.GetAuthenticationTokenAsync();
         return Ok(token);
}

here is the AuthService code which is called from AuthController

public async Task<string> GetAuthenticationTokenAsync(){
      HttpClient client = new HttpClient();
       var response = await client.SendAsync(request, 
       HttpCompletionOption.ResponseContentRead);
       response.EnsureSuccessStatusCode();
       var token = await response.Content.ReadAsStringAsync();
       return token;
}

extra information. test method for mocked controller works fine. it seems the problem is in second step usage of the mocked controller. the first step works fine. I mean I can access the mocked controller from Test unit at first step but when I try to access it through the Main controller(AuthController), I can't get to it

1 Answers

Your code is too tightly coupled to implementation concerns to allow for components to be mocked to isolate it from 3rd party dependencies. Because HttpClient is created manually there is no way to replace its handler to fake the requests.

Consider mocking the auth service itself that is injected into the controller under test.

For example

//...

var token = "{fake token here}";
var authService = Mock.Of<IAuthService>(_ =>
    _.GetAuthenticationTokenAsync == Task.FromResult(token)
);

config.AddSingleton<IAuthService>(authService);

//...
Related