【问题标题】:How Can We Create Unit Tests For Webapi With 3rd Party API's我们如何使用 3rd 方 API 为 Web Api 创建单元测试
【发布时间】:2016-10-03 09:42:14
【问题描述】:

我正在使用 Nunit 创建单元测试。我有 webapi 项目并使用一些第三方 api 下面是我正在使用的代码块之一。

在下面的函数中,您可以看到我正在返回 facebook graph api 以字符串格式返回的 json 数据。至于单元测试断言 IsEqual 检查我的两个比较对象将使用来自同一个 api 的数据然后我需要匹配它们还是需要对此类项目进行测试。

public  string getfriends(string accesstoken)
        {
            string retVal = "";
            string url = API_BaseUrl + "/me/invitable_friends?&access_token=" + accesstoken;
            System.Net.HttpWebRequest request = System.Net.WebRequest.Create(url) as System.Net.HttpWebRequest;
            System.Net.HttpWebResponse response = null;
            try
            {
                using (response = request.GetResponse() as System.Net.HttpWebResponse)
                {
                    System.IO.StreamReader reader = new System.IO.StreamReader(response.GetResponseStream());
                    retVal = reader.ReadToEnd();
                }
            }
            catch (Exception ex)
            {

            }
            return retVal;
        }

【问题讨论】:

  • 研究抽象您的依赖项(在本例中为第 3 方 API)并将它们注入到它们的依赖类中。这将允许更好地模拟您的单元测试和整体上更灵活/可维护的架构。
  • @Nkosi 一个简单的问题,为什么我需要改进代码,我只是展示了返回从 fb graph api 返回的字符串数据 (json) 的代码示例,我需要对其进行单元测试跨度>

标签: c# api unit-testing asp.net-web-api nunit


【解决方案1】:

研究抽象您的依赖项(在本例中为 3rd 方 API)并将它们注入到它们的依赖类中。这将允许更好地模拟您的单元测试和整体上更灵活/可维护的架构。

以您当前的函数为例,抽象看起来像这样。

public interface IFacebookService {
    public string GetFriends();
}

public interface ITokenProvider {
    public string GetAccessToken();
}

这里接口的实现要有实际代码连接到第3方服务。

public class FacebookService : IFacebookService
    private string accesstoken;
    private string API_BaseUrl;

    public FacebookService(ITokenProvider tokens, IUrlProvider urls) {
        accessToken = tokens.GetAccessToken();
        API_BaseUrl = url.GetBaseUrl();
    }

    public  string Getfriends() {
        string retVal = "";
        string url = API_BaseUrl + "/me/invitable_friends?&access_token=" + accesstoken;
        System.Net.HttpWebRequest request = System.Net.WebRequest.Create(url) as System.Net.HttpWebRequest;
        System.Net.HttpWebResponse response = null;
        try {
            using (response = request.GetResponse() as System.Net.HttpWebResponse) {
                System.IO.StreamReader reader = new System.IO.StreamReader(response.GetResponseStream());
                retVal = reader.ReadToEnd();
            }
        }
        catch (Exception ex)
        {

        }
        return retVal;
    }
}

例如,如果您有一个依赖于该服务的 API 控制器。

public class FriendsController : ApiController {
    IFacebookService facebook;

    public FriendsController(IFacebookService facebook) {
        this.facebook = facebook;
    }

    [HttpGet]
    public IHttpActionResult GetFacebookFriends() {
        var friends = facebook.GetFriends();
        if(!string.IsNullOrWhiteSpace(friends)) {
            return Ok(friends);
        }
        return NotFound("You have no friends. :(");
    }
}

对于独立的单元测试,您现在可以模拟已抽象的第 3 方 API。我正在使用 Moq 来模拟第 3 方抽象。

[TestClass]
public class FriendsControllerTests {
    [TestMethod]
    public void GetFacebookFriendsTest() {
        //Arrange
        var facebook = Mock.Of<IFacebookService>();
        var facebookMock = Mock.Get(facebook);
        facebookMock.Setup(m => m.GetFriends()).Returns("{json of friends}");

        var sut = new FriendsController(facebook);

        //Act
        var actionResult = sut.GetFacebookFriends();

        //Assert
        //...do your assertions here 
    }
}

上述测试现在允许您单独测试控制器,而无需直接调用实际的第 3 方 API。

【讨论】:

    【解决方案2】:

    我会抽象出您的消息发送/检索,然后单独对其进行单元测试,并且无论哪个类也包含您的 GetFriends 隔离,模拟消息发送/检索。

    您应该对所有项目进行单元测试,但代码需要以可行的方式设计。目前这段代码很难测试,因为它正在启动 HttpWebRequests,需要在某种接口后面隔离,称为 IRequestSender。我推荐 Moq 来模拟接口,不模拟你会发现测试就像用头撞墙。

    【讨论】:

    • 去检查起订量和 IRequestSender 。我已经通过接口和其他东西管理了带有数据库操作的体系结构,但是要为 httpwebrequest 找到隔离
    • IRequestSender 是我刚刚编的一个接口名称,如果您使用的 API 没有与之交互的接口,我建议您围绕它创建自己的接口包装器,以允许您模拟出来 - 这就是我的 IRequestSender 名称将用作包装器名称的地方。我不确定标准的 .Net WebRequests 是否有一个使用它们的接口,我怀疑没有......不过看看 Moq,并考虑如何从你的代码库的其余部分隐藏具体的类,你应该能够从那里弄清楚
    • 是的,我想我需要打破这个提供的函数的内部代码你有什么例子我将如何测试它在这种情况下我们正在接近 api 函数以返回 json 数据以及我将如何提供任何好处
    • 我现在已经改进了代码版本,但问题是在这种情况下进行单元测试是否正确?我这样说是因为我们正在请求第 3 方 api
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-09
    • 2013-10-10
    相关资源
    最近更新 更多