【问题标题】:Unit testing Web Service responses单元测试 Web 服务响应
【发布时间】:2014-02-13 23:56:32
【问题描述】:

我目前正在用 C# 为 ResellerClub 的 REST/HTTP API 编写一个 API 包装器,它以各种 JSON 对象的形式提供响应。通过使用 HttpClient 类在 API 端点上执行 HTTP POST/GET 来执行调用。 JSON.Net 用于解析响应。

如何对 API 的 API 包装器功能进行单元测试,因为大多数调用都需要一定级别的预期状态才能成功。例如,我无法在尚未注册的域上测试 CNAME 记录的创建。

我知道测试不应该依赖于它们自己没有安排的状态,而且我还被告知测试不应该真正处理任何类型的持久性机制,例如数据库。那么,对于上面的 CNAME 记录示例,作为测试的“安排”阶段的一部分,我应该注册一个测试域,断言它有效,然后执行实际的 CNAME 功能?

或者,我是否应该想出一些方法来模拟从 Reseller Club API 返回的 JSON 响应?

编辑:我的 API 类示例 (ResellerClubApi.cs)

private async Task<string> DownloadString(string uri) 
{
   // HttpClient object downloads the JSON response string asynchronously
}

DownloadString() 方法被我的功能用作从第三方服务获取响应的通用方法。

public async Task<List<string>> SuggestNames(string domainName) 
{
   // Calls DownloadString() with the correct URI, uses Newtonsoft.JSON to parse 
   // string representation of JSON into object
}

上面的SuggestNames()等方法从更高的服务层这样调用

public void someServiceLayerMethod() 
{
   var rcApi = new ResellerClubApi();

   var x = rcApi.SuggestNames("something");

   // ...

}

如您所见,当我的 ResellerClubApi 类在通过 HTTP 执行操作之前是我自己的代码的最低可能层时,我对如何模拟来自 HttpClient 之类的 JSON 响应有点困惑。

我也不知道如何开始使用 IoC 来处理 HttpClient 依赖...

谢谢

【问题讨论】:

  • 你有一些示例代码来看看你的类是如何制作的吗?你使用依赖注入/控制反转吗?
  • @Tseng 我添加了一些代码示例,希望对您有所帮助。

标签: c# unit-testing testing dependency-injection dotnet-httpclient


【解决方案1】:

我会将代码与您的 ResellerClubApi 类分开,该类涉及下载内容和授权,以及涉及连接到远程服务的所有内容,比如说 ResellerClubClient 并让它实现 IResellerClubClient 接口。

public interface IResellerClubClient {
    string RequestJson(string url);
}

public class ResellerClubClient : IResellerClubClient {
    // implement your methods here 
}

public ResellerClubApi : IResellerClubApi {
    private readonly IResellerClubClient client;
    // Pass the client as dependency, either manually or using Dependency framework of your choice
    public ResellerClubApi(IResellerClubClient client) {
        this.client = client;
    }

    public List<string> SuggestNames(string domainName) {
        var jsonString = this.client.RequestJson("http://example.com/domains/?name="+domainName);
        // decode it and do something with it
    }
}

这允许您测试您的ResellerClubApi 类,而不依赖于具体的IResellerClubClient 实现。最好的是,您可以更改它(从 HttpClient 到 socket 或其他任何东西,而不必触摸您的 ResellerClubApi

然后在您选择的框架中设置您的单元测试。 Moq 框架的一些示例:

var mockedJsonString = '{ succes: true, names: ["domainA.com", "domainA.us"] }';

// create mockup object using IResellerClubClient interface
var resellerClubClient = new Mock<IResellerClubClient>();
// Tell the mock object to return "mockedJsonString" when any parameter is passed to RequestJsonString. 
// If you do more than 1 call in a test, or if that's expected to be called multiple times inside
// the method to be tested, you can setup multiple conditions and results this way too
resellerClubClient.Setup(x => x.RequestJson(It.IsAny<string>())).Returns(mockedJsonString);

var api = new ResellerClubApi(resellerClubClient.Object);
List<string> names = api.SuggestNames("domain.com");

// do your assertions here 

通过将连接和数据检索方法抽象为由接口表示的 hit 自己的类,您使您的 Api 类 UnitTestable 并且易于模拟服务器响应。

当然,ResellerClubClient 当然不能进行单元测试。但它可以在集成测试或验证测试中完成。 UnitTest 不应涉及连接到服务器或数据库。

【讨论】:

  • 这太棒了。非常感谢您的详细回复!
【解决方案2】:

这是一种使用 Moq 单元测试模拟 HttpMessageHandler 的方法。 http://geekswithblogs.net/abhi/archive/2013/11/20/unit-tests-for-httpclient-using-httpmessagehandler.aspx

【讨论】:

    猜你喜欢
    • 2011-02-03
    • 1970-01-01
    • 1970-01-01
    • 2011-04-30
    • 2019-05-29
    • 1970-01-01
    • 2015-05-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多