简体   繁体   English

如何测试具有私有方法依赖项的公共函数?

[英]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:所以,你可以:

  1. 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));...

  2. 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.

相关问题 如何对利用私有财产的公共方法进行单元测试? - How do I unit test a public method which utilizes a private property? 我应该如何测试访问私有成员的公共方法 - How should I test a public method that access a private member 如何对依赖于基类的方法进行单元测试? - How do I unit test the method which has dependency on base classes? 如何在 MVP 模式中对具有私有方法的公共方法进行单元测试 - How to unit-test a public method that has private methods in MVP pattern 您如何测试私有方法内部的异常,该方法由公共 void 使用? - How do you test for an exception that is inside of a private method, which is used by a public void? 如何在setter C#中测试私有方法 - How do I test a private method inside a setter c# 如何使用 xUnit 对具有私有方法和字段的类进行单元测试? - How do I unit test a class that has private methods and fields using xUnit? NUnit 测试 - 如何设置在公共方法内部调用的私有方法以返回特定值? - NUnit Test - How to set up a private method called inside public method to return specific value? 如何使用 Moq C# 在公共方法中对私有方法进行单元测试? - How to unit test a private method inside a public method using Moq C#? 如何在RSAParameters上设置公钥和私钥以用于RSACryptoServiceProvider? - How do I set the public and private key on RSAParameters to use for RSACryptoServiceProvider?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM