单元测试Web服务响应 [英] Unit testing Web Service responses

查看:90
本文介绍了单元测试Web服务响应的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am currently writing an API wrapper in C# for ResellerClub's REST/HTTP API, which provides responses in garden-variety JSON objects. Invocation is performed by performing HTTP POST/GET on API endpoints using the HttpClient class. JSON.Net is used for parsing the responses.

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

How I can unit test my API wrapper functionality for the API as most calls require a level of expected state in order to succeed. For example, I cannot test the creation of a CNAME record on a domain that I have not already registered.

我知道测试永远都不应依赖于它们未声明的状态安排自己,我还被告知,测试实际上不应该处理任何种类的持久性机制,例如数据库。那么,对于上面的CNAME记录示例,在测试的安排阶段中,我应该注册一个测试域,断言它可以工作,然后执行实际的CNAME功能?

I understand that tests should never rely on state which they do not arrange themselves, and I've also been told that the tests should never actually deal with any kind of persistence mechanism such as a database. So, for the above example of a CNAME record, that as part of the "Arrange" phase of the test I should register a test domain, assert it worked, then do the actual CNAME function?

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

Alternative, should I come up with some way of mocking the JSON responses that are returned from the Reseller Club API?

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

Example of my API class (ResellerClubApi.cs)

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

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

The DownloadString() method is used by my functionality as a generic means of grabbing the response from the third party service.

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()一样被调用

Methods such as SuggestNames() above are called like this from the higher service layer

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

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

   // ...

}

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

As you can see, I am a bit stuck as to how to mock JSON responses from the likes of HttpClient when my ResellerClubApi class is the lowest possible layer of my own code prior to doing things over HTTP.

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

I also don't know how to start using IoC to hand the HttpClient dependency...

谢谢

推荐答案

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

I would separate the code from your ResellerClubApi class which involves downloading stuff and authorization, and everything that involves connecting to a remote service, in let's say a ResellerClubClient and have it implement a IResellerClubClient interface.

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 更改为套接字或其他,而无需触摸您的 ResellerClubApi

This allows you to test your ResellerClubApi class without being depending on a concrete IResellerClubClient implementation. And the best is, you can change it (from HttpClient to socket or whatever and don't ever have to touch your ResellerClubApi.

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

And then set up your Unit test in framework of your choice. Some example with Moq framework:

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并易于模拟服务器响应。

By having abstracted the connection and data retrieving methods into hit's own class represented by an interface, you made your Api class UnitTestable and easy to mock server responses.

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

Of course, the ResellerClubClient can't be Unit tested of course. But it can be done in an integration test or a verification test. A UnitTest should never involve connecting to a server or a database.

这篇关于单元测试Web服务响应的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆