3

非同期メソッドから正しい型が返されるかどうかをテストしたい。このメソッドは、依存関係クラスで別の非同期メソッドを使用します。依存関係クラスは、次のインターフェイスを実装します。

Task<string> DownloadStringAsync(string url);

私がテストしたい方法はこれです:

public async Task<T> GetData<T>(string url) where T : class , new()
{
    var jsonData = await _webClientWrapper.DownloadStringAsync(url);

    if (string.IsNullOrEmpty(jsonData))
        return new T();

    try
    {
        return await JsonConvert.DeserializeObjectAsync<T>(jsonData);
    }
    catch (JsonException inner)
    {
        throw new JsonConvertException("Error converting Json string", inner) { JsonString = jsonData };
    }
}

xUnit と Moq を使用したテストは成功します。

public class Testes
{
    private const string ValidJson = "{'Nome':'Rogerio','Idade':'51'}";
    protected static JsonWebServiceClassProvider JsonWebServiceClassProvider;
    private static Mock<IWebClientWrapper> _webClientWrapperMoq;
    private static FakeClassFromJson _resultClass;

    [Fact]
    public async static void When_calling_GetData_it_should_return_a_class_of_same_type()
    {
        _webClientWrapperMoq = new Mock<IWebClientWrapper>();
        _webClientWrapperMoq
            .Setup(w => w.DownloadStringAsync(Moq.It.IsAny<string>()))
            .Returns(Task.FromResult(ValidJson));

        JsonWebServiceClassProvider = new JsonWebServiceClassProvider(_webClientWrapperMoq.Object);

        _resultClass = await JsonWebServiceClassProvider
            .GetData<FakeClassFromJson>(Moq.It.IsAny<string>());

        Assert.IsType<FakeClassFromJson>(_resultClass);
    }
}

MSpec と Moq を使用したテスト:

[Subject("JsonWebServiceClassProvider")]
public class When_calling_GetData_with_a_valid_Json_Service_Url
{
    private const string ValidJson = "{'Nome':'Rogerio','Idade':'51'}";
    protected static JsonWebServiceClassProvider JsonWebServiceClassProvider;
    protected static Mock<IWebClientWrapper> WebClientWrapperMoq;
    protected static FakeClassFromJson ResultClass;

    Establish context = () =>
    {
        WebClientWrapperMoq = new Mock<IWebClientWrapper>();
        WebClientWrapperMoq
            .Setup(w => w.DownloadStringAsync(Moq.It.IsAny<string>()))
            .Returns(Task.FromResult(ValidJson));

        JsonWebServiceClassProvider = new JsonWebServiceClassProvider(WebClientWrapperMoq.Object);
    };

    Because of = () => ResultClass = JsonWebServiceClassProvider
        .GetData<FakeClassFromJson>(Moq.It.IsAny<string>())
        .Await();

    It should_return_a_class_of_same_type = () => ResultClass.ShouldBeOfType<FakeClassFromJson>();
}

Becauseこれらのステートメントでも失敗します

Because of = () => JsonWebServiceClassProvider
    .GetData<FakeClassFromJson>(Moq.It.IsAny<string>())
    .ContinueWith(task => ResultClass = task.Result)
    .Wait();

Because of = () => ResultClass = JsonWebServiceClassProvider
    .GetData<FakeClassFromJson>(Moq.It.IsAny<string>())
    .Result;

NullReferenceExceptionこれは行に a で失敗します

public async Task<T> GetData<T>(string url) where T : class , new()
{
    string jsonData = await _webClientWrapper.DownloadStringAsync(url);
    // ...
}

解決した

応答を待っている間に、いくつかのリファクタリングを行い、出来上がりました! ステートメントを使用して基本クラスを作成し、Establishそこでモック オブジェクトを開始しました。

public class JsonWebServiceClassProviderSpecs
{
    protected static JsonWebServiceClassProvider JsonWebServiceClassProvider;
    protected static Mock<IWebClientWrapper> WebClientWrapperMoq; 

    Establish context = () =>
    {
        WebClientWrapperMoq = new Mock<IWebClientWrapper>();
        JsonWebServiceClassProvider = new JsonWebServiceClassProvider(WebClientWrapperMoq.Object);
    };
}

そして、テストクラスを更新しました:

[Subject("JsonWebServiceClassProvider")]
public class When_ask_data_with_a_valid_Json_Service_Url : JsonWebServiceClassProviderSpecs
{
    private const string ValidJson = "{'Nome':'Rogerio','Idade':'51'}";
    protected static FakeClassFromJson ResultClass;

    Establish context = () =>
    {
        WebClientWrapperMoq
            .Setup(w => w.DownloadStringAsync(Moq.It.IsAny<string>()))
            .Returns(Task.FromResult(ValidJson));
    };

    Because of = () => ResultClass = JsonWebServiceClassProvider
        .GetData<FakeClassFromJson>(Moq.It.IsAny<string>())
        .Await();

    It should_return_a_class_of_same_type = () => ResultClass.ShouldBeOfType<FakeClassFromJson>();
}
4

2 に答える 2

4

これは、機能する仕様のスリム化されたバージョンです。いいえNullReferenceException、見られません。ノート:

  • はのIt型をチェックしませんAwaitResultが、ラップされたものを取得しますTask.Result
  • ノイズMoq.It<string>.Any...Because多すぎます。パラメータが無視される場合は、その事実を伝える値を使用してください。

(以下のコード ブロックが正しくフォーマットされるようなテキストのみです。)

using System.Diagnostics;
using System.Threading.Tasks;

using Machine.Specifications;

using Moq;

using YourApp;

using It = Machine.Specifications.It;

namespace YourApp
{
  class Foo
  {
  }

  public interface IWebClientWrapper
  {
    Task<string> DownloadStringAsync(string url);
  }

  public class JsonWebServiceClassProvider
  {
    readonly IWebClientWrapper _webClientWrapper;

    public JsonWebServiceClassProvider(IWebClientWrapper webClientWrapper)
    {
      _webClientWrapper = webClientWrapper;
    }

    public async Task<T> GetData<T>(string url) where T : class, new()
    {
      string jsonData = await _webClientWrapper.DownloadStringAsync(url);
      Debug.Assert(jsonData != null);
      return new T();
    }
  }
}

namespace Specs
{
  public class When_calling_GetData_with_a_valid_Json_Service_Url
  {
    const string ValidJson = "{'Nome':'Rogerio','Idade':'51'}";
    static JsonWebServiceClassProvider JsonWebServiceClassProvider;
    static Mock<IWebClientWrapper> Wrapper;
    static AwaitResult<Foo> Result;

    Establish context = () =>
    {
      Wrapper = new Mock<IWebClientWrapper>();
      Wrapper.Setup(w => w.DownloadStringAsync(Moq.It.IsAny<string>()))
             .Returns(Task.FromResult(ValidJson));

      JsonWebServiceClassProvider = new JsonWebServiceClassProvider(Wrapper.Object);
    };

    Because of = () => Result = JsonWebServiceClassProvider.GetData<Foo>("ignored").Await();

    It should_return_a_class_of_same_type = () => Result.AsTask.Result.ShouldBeOfType<Foo>();
  }
}
于 2013-07-07T07:13:42.467 に答える