最小起订量测试 - 模拟服务呼叫始终返回 null



我是一般的最小起订量和模拟/单元测试的新手。在观看了使用Moq的Mocking视频后,我认为我有足够的理解,可以开始为我正在从事的项目设置一些简单的测试。 但是,再多的摆弄代码都无助于我的第一次测试通过。

这是我的代码:

正在测试的接口

public interface IDataInterface
{
Task<IList<T>> GetData<T>(string url);
// Other stuff
}

接口方法GetData

public async Task<IList<T>> GetData<T>(string url)
{
try
{
var json = await client.GetAsync(url).Result.Content.ReadAsStringAsync();
var data = (JObject)JsonConvert.DeserializeObject(json);
JArray arr = (JArray)data["resource"];
return arr.ToObject<IList<T>>();
}
catch (InvalidCastException icEx)
{
throw new InvalidCastException("An error occurred when retrieving the data", icEx);
}
// Other catches
}

服务调用实现的接口 GetData

public async Task<IList<MyObj>> GetActiveObjs()
{
var data = await _myImplementedInterface.GetData<MyObj>(ActiveUrl);
return data;
}

我的测试

[Fact]
public async void MyImplementedInterface_GetActive_ReturnsDataOrEmptyList()
{
var _activeUrl = "http://some.url";
using (var mock = AutoMock.GetLoose())
{
mock.Mock<IDataInterface>()
.Setup(x => x.GetData<MyObj>(_activeUrl))
.Returns(Task.FromResult(_SomeStaticDataRepresentation)));
var svc = mock.Create<MyService>();
var expected = _SomeStaticDataRepresentation;
var actual = await svc.GetActiveObjs();
Assert.True(actual != null);
// Other assertions that never matter because of the null value of _actual_ variable
}
}

早期,我遇到了问题,因为该项目使用 Autofac 和 Moq,但我解决了这些特定问题。 但是,我似乎无法通过从服务调用返回的空值。 运行项目时,该方法会返回数据,正如预期的那样,所以我对问题所在感到困惑。 查看各种帖子和 Moq 快速入门并没有提供我自己解决这个问题所需的内容,所以我希望这里有人可以告诉我我做错了什么。 我已经道歉了,因为我确信这是一个新手错误。

首先解决实现问题。避免混合使用异步等待和阻止Wait().Result等调用,这可能会导致死锁。

参考异步/等待 - 异步编程的最佳实践

public async Task<IList<T>> GetData<T>(string url) {
try {
var response = await client.GetAsync(url);
var json = await response.Content.ReadAsStringAsync();
var data = (JObject)JsonConvert.DeserializeObject(json);
JArray arr = (JArray)data["resource"];
return arr.ToObject<IList<T>>();
} catch (InvalidCastException icEx) {
throw new InvalidCastException("An error occurred when retrieving the data", icEx);
}
// Other catches
}

对于被测试的主题方法,如果不需要等待任何内容,则无需使函数异步,只需返回Task

public Task<IList<MyObj>> GetActiveObjs() {
return _myImplementedInterface.GetData<MyObj>(ActiveUrl);
}

现在进行测试,由于已经使用了任务,那么测试应该是异步的,并且受试者也在等待。

[Fact]
public async Task MyImplementedInterface_GetActive_ReturnsDataOrEmptyList() {
using (var mock = AutoMock.GetLoose()) {
//Arrange
IList<MyObj> expected = _SomeStaticDataRepresentation;
mock.Mock<IDataInterface>()
.Setup(x => x.GetData<MyObj>(It.IsAny<string>()))
.ReturnAsync(expected);
var svc = mock.Create<MyService>();
//Act
var actual = await svc.GetActiveObjs();
//Assert
Assert.True(actual != null);
Assert.True(actual == expected);
// ...
}
}

假设根据显示的内容不确定活动 URL 会是什么,则可以使用It.IsAny<string>()在测试中忽略它。

最新更新