单元测试Web服务响应

时间:2014-02-13 23:56:33

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

我目前正在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依赖...

由于

2 个答案:

答案 0 :(得分:1)

这是通过使用Moq单元测试模拟HttpMessageHandler来实现的。 http://geekswithblogs.net/abhi/archive/2013/11/20/unit-tests-for-httpclient-using-httpmessagehandler.aspx

答案 1 :(得分:1)

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

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

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

ResellerClubApi

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

当然,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 当然不能进行单元测试。但它可以在集成测试或验证测试中完成。 UnitTest 永远不应该涉及连接到服务器或数据库。