我们如何使用第三方API为Webapi创建单元测试

时间:2016-10-03 09:42:14

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

我正在使用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;
        }

2 个答案:

答案 0 :(得分:4)

查看抽象依赖项(在本例中为第三方API)并将它们注入其依赖类。这样可以更好地模拟单元测试,并提供更灵活/可维护的体系结构。

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

public interface IFacebookService {
    public string GetFriends();
}

public interface ITokenProvider {
    public string GetAccessToken();
}

此接口的实现具有连接第三方服务的实际代码。

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. :(");
    }
}

对于隔离的单元测试,您现在可以模拟已抽象的第三方API。我正在使用Moq模拟第三方抽象。

[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 
    }
}

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

答案 1 :(得分:2)

我将你的信息发送/检索抽象出来,然后单独进行单独测试。无论哪个类都孤立地包含你的GetFriends,嘲笑发送/检索的消息。

您应该对所有项目进行单元测试,但代码需要以可行的方式进行设计。目前这个代码很难测试,因为它正在启动HttpWebRequests,它需要被隔离在某种界面后面,称为IRequestSender。我建议Moq嘲笑接口,不要嘲笑你会发现测试就像撞墙一样。