简体   繁体   English

如何在Windows Phone上对使用Web服务的方法进行单元测试?

[英]How to Unit Test method that uses a Webservice on Windows Phone?

I'm working on a project that retrieves information from an external webservice API, but I'm not sure how I'm supposed to test it, I'm quite new at Testing and I have done just a couple of Unit Test, but as far as I know I have to mock the webservice functionality, I've been looking for info regarding this subject but haven't found anything for Windows Phone yet. 我正在一个项目中,该项目从外部Web服务API检索信息,但是我不确定如何测试它,我在Testing中是一个新手,并且只做了几次单元测试,但是据我所知我必须模拟Web服务功能,我一直在寻找有关此主题的信息,但尚未为Windows Phone找到任何东西。 What's the standard procedure for these type of cases? 这些案件的标准程序是什么?

Here's a simple version of what I want to test: 这是我要测试的简单版本:

    public async Task<List<Song>> FetchSongsAsync(String query)
    {
        if (String.IsNullOrEmpty(query))
            return null;

        string requestUrl = "webservice url";
        var client = new HttpClient();
        var result = await client.GetStringAsync(new Uri(requestUrl,UriKind.Absolute));
        try
        {
            var result = JsonConvert.DeserializeObject<RootObject>(result);
            return result;
        }
        catch (Exception)
        {
            return null;
         }
    }

Thanks! 谢谢!

Decouple your code from its dependencies: make content loading and its deserialization replaceable : 分离从它的依赖您的代码:使内容加载和反序列化的更换

private readonly IClient client;
private readonly ISerializer serializer;

public YourService(IClient client, ISerializer serializer)
{
    _client = client;
    _serializer = serializer;
}

public async Task<List<Song>> FetchSongsAsync(String query)
{
    try
    {
        var result = await _client.GetStringAsync(new Uri("http://example.com"));
        return _serializer.DeserializeObject<RootObject>(result);
    }
    catch (Exception)
    {
        return null;
    }
}

The first thing that may help is understand and use dependency injection. 可能有帮助的第一件事是了解并使用依赖项注入。 Basically taking any dependencies of your object/method/etc and (as it states) injecting them into the object/method/etc. 基本上获取对象/方法/等的任何依赖关系,并将其注入到对象/方法/等中。 For example, you are having a difficult time figuring out how to test the method because the method depends on being able to access the web service. 例如,您很难确定如何测试该方法,因为该方法取决于能否访问Web服务。 There are a couple things you can do after this. 此后您可以做几件事。

One thing to do is to check out mocking frameworks such as Moq . 要做的一件事是检查Moq模拟框架。

Another thing I recently did was I added an overloaded constructor (dependency injection) that takes a HttpMessageInvoker object (note HttpClient derives from this). 我最近做的另一件事是我添加了一个HttpMessageInvoker对象的重载构造函数(依赖注入)(注意HttpClient从此派生)。 This way I could instantiate the class with my own response message: 这样,我可以使用自己的响应消息实例化该类:

public class MyLoader()
{
    protected HttpMessageInvoker MessageInvoker { get; set; }
    private HttpRequestMessage requestMessage;

    public MyLoader()    // default constructor
    {
        MessageInvoker = new HttpClient();
    }

    public MyLoader(HttpMessageInvoker httpMessageInvoker)
    {
        MessageInvoker = httpMessageInvoker;
    }

    public object DoSomething()
    {
        var response = await MessageInvoker.SendAsync(requestMessage, cancellationTokenSource.Token);
    }

Here is my mock message invoker: 这是我的模拟消息调用程序:

public class MockMessageInvoker : HttpMessageInvoker
{
    public string ResponseString { get; set; }

    public MockMessageInvoker(string responseString)
        : base(new HttpClientHandler())
    {
        ResponseString = responseString;
    }

    public override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
    {
        return Task.Run<HttpResponseMessage>(() =>
        {
            HttpResponseMessage responseMessage = new HttpResponseMessage(
                System.Net.HttpStatusCode.OK);

            var bytes = Encoding.ASCII.GetBytes(ResponseString);
            var stream = new System.IO.MemoryStream(bytes);

            responseMessage.Content = new StreamContent(stream);
            return responseMessage;
        });

    }
}

I can call it all like so: 我可以这样称呼它:

MyLoader loader = new MyLoader(new MockMessageInvoker(validJsonResponse));
loader.DoSomething() // I've removed the dependency on the service and have control of the content in the response

It's quick and dirty, but does the trick. 它既快又脏,但是可以解决问题。

Hope this helps. 希望这可以帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM