[英]How do I test a public function that has private method dependency?
I'm trying to test a public method (Method A) that consumes an HttpClient to access an external API.我正在尝试测试使用 HttpClient 来访问外部 API 的公共方法(方法 A)。 This public method calls a private method (Method B) of the same class to get an Access Token that is required by the HttpClient of Method A to send the request.这个公共方法调用同一个类的私有方法(方法B)来获取方法A的HttpClient发送请求所需的Access Token。 The problem I am having is that I am creating a mock of the HttpClientFactory interface in order to test the response of the Method A, but in order for Method B get the token it needs its own instance of HttpClient.我遇到的问题是我正在创建 HttpClientFactory 接口的模拟以测试方法 A 的响应,但为了让方法 B 获取令牌,它需要自己的 HttpClient 实例。 Therefore, the mock instance created in the Test method will be used by the Method B as well, and it will fail trying to get the Access Token.因此,Test 方法中创建的模拟实例也将被方法 B 使用,并且尝试获取访问令牌将失败。 The following code makes the scenario more clear.下面的代码使场景更加清晰。
Method to be tested (Method A):待测方法(方法A):
public async Task<HttpResponseMessage> SendAsync(string requestUri, string siteName, int accountId)
{
try
{
var accessToken = await GetTokenAsync(siteName, accountId);
if (accessToken == null)
throw new ArgumentNullException("Error Sending request - Could not find an access token");
var request = new HttpRequestMessage(HttpMethod.Get, $"{accessToken.Api}{requestUri}");
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken.Accesstoken);
var httpClient = _httpClientFactory.CreateClient();
return await httpClient.SendAsync(request);
}
catch (Exception e)
{
throw new Exception("Error Sending request.", e);
}
}
Test Method:测试方法:
[Fact]
public async Task ShouldReturnHttpResponseMessage_OnSendAsync()
{
//_jaClientMock.Setup(x => x.GetTokenAsync(It.IsAny<string>(), It.IsAny<int>())).Verifiable();
_appSettingsMock.Setup(x => x.Value)
.Returns(GetValidFakeAppSettings());
HttpResponseMessage expectedResponse = GetListOfContacts(HttpStatusCode.OK, false);
_httpClientFactoryMock.Setup(x => x.CreateClient())
.Returns(GetMockedHttpClient(expectedResponse));
var response = await _jaClient.SendAsync("someurl", "siteName", 1000);
response.IsSuccessStatusCode.ShouldBeTrue();
}
The private Method (Method B):私有方法(方法B):
private async Task<AccessToken> GetTokenAsync(string siteName, int accountId)
{
try
{
if (_cache.TryGetValue(GetCacheKeyForToken(siteName, accountId), out AccessToken value))
return value;
....
var httpClient = _httpClientFactory.CreateClient();
var response = await httpClient.SendAsync(request);
if (response.IsSuccessStatusCode)
{
accessToken = await response.Content.ReadAsAsync<AccessToken>();
}
.....
return accessToken;
}
catch (Exception e)
{
throw new Exception("Error Getting an Access Token.", e);
}
}
Any idea How I can test Method A?知道如何测试方法 A 吗?
There ain't no such thing as a free lunch - if one wants to unit-test some code with external dependencies, then each and every of those external dependencies has to be mocked . 天下没有免费的午餐——如果你想对一些带有外部依赖的代码进行单元测试,那么每个外部依赖都必须被模拟。
Or one can go one step up the test pyramid to integration tests (though it is not our case, probably).或者你可以在 测试金字塔上更进一步进行集成测试(尽管这可能不是我们的情况)。
So, you could:所以,你可以:
Either mock the Token response in the _httpClientFactory
the same way you mock it for the SendAsync
( ..._httpClientFactoryMock.Setup(x => x.CreateClient()).Returns(GetMockedHttpClient(expectedResponse));...
)在_httpClientFactory
模拟 Token 响应的方式与为SendAsync
模拟它的方式相同( ..._httpClientFactoryMock.Setup(x => x.CreateClient()).Returns(GetMockedHttpClient(expectedResponse));...
)
Or reorganize code in such a manner that tokens are not retrieved directly from API - create some single-method ITokenProvider
interface that will be a bit easier to mock.或者以不直接从 API 检索令牌的方式重新组织代码 - 创建一些更容易模拟的单方法ITokenProvider
接口。
public interface ITokenProvider { public async Task<AccessToken> GetTokenAsync(string siteName, int accountId); } ... public async Task<HttpResponseMessage> SendAsync(string requestUri, string siteName, int accountId) { try { var accessToken = await _tokenProvider.GetTokenAsync(siteName, accountId); ... [Fact] public async Task ShouldReturnHttpResponseMessage_OnSendAsync() { var tokenProviderMock = new Mock<ITokenProvider>() .Setup(o => o.GetTokenAsync("siteName", 1000)) .Returns(Constants.AllowedToken); _jaClient = new JaClient(tokenProviderMock.Object);...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.