gpt4 book ai didi

c# - 为什么在使用 MSpec/Moq 测试此异步方法时会出现 NullReferenceException?

转载 作者:行者123 更新时间:2023-11-30 15:33:29 25 4
gpt4 key购买 nike

我想测试从异步方法返回的类型是否正确。此方法在依赖类中使用另一个异步方法。依赖类实现了这个接口(interface):

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

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

最佳答案

这是您的规范的精简版。没有 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>();
}
}

关于c# - 为什么在使用 MSpec/Moq 测试此异步方法时会出现 NullReferenceException?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17503287/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com