最小起订量测试 - 模拟服务调用总是 Returns Null
Moq Test - Mocked Service Call Always Returns Null
我是 Moq 新手,Mocks/Unit 一般测试。看完 a video on Mocking which uses Moq 之后,我认为我已经有了足够的了解,可以开始为我正在从事的项目设置一些简单的测试。然而,再多的代码修改也无法帮助我通过第一次测试。
这是我的代码:
接口正在测试
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,但我解决了这些具体问题。但是,我似乎无法通过从服务调用返回的空值。当运行项目时,方法returns数据,果然不出所料,所以我很困惑问题出在哪里。查看各种帖子和 Moq Quickstart 没有提供我自己解决这个问题所需的东西,所以我希望这里有人可以告诉我我做错了什么。我已经道歉,因为我确定这是一个新手错误。
首先解决实施问题。避免混合异步等待和阻塞调用,例如 Wait()
和 .Result
,这可能会导致死锁。
引用Async/Await - Best Practices in Asynchronous Programming
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
}
对于被测的主题方法,如果不需要等待那么函数就不需要异步,只需return 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>()
的测试中忽略它。
我是 Moq 新手,Mocks/Unit 一般测试。看完 a video on Mocking which uses Moq 之后,我认为我已经有了足够的了解,可以开始为我正在从事的项目设置一些简单的测试。然而,再多的代码修改也无法帮助我通过第一次测试。
这是我的代码:
接口正在测试
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,但我解决了这些具体问题。但是,我似乎无法通过从服务调用返回的空值。当运行项目时,方法returns数据,果然不出所料,所以我很困惑问题出在哪里。查看各种帖子和 Moq Quickstart 没有提供我自己解决这个问题所需的东西,所以我希望这里有人可以告诉我我做错了什么。我已经道歉,因为我确定这是一个新手错误。
首先解决实施问题。避免混合异步等待和阻塞调用,例如 Wait()
和 .Result
,这可能会导致死锁。
引用Async/Await - Best Practices in Asynchronous Programming
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
}
对于被测的主题方法,如果不需要等待那么函数就不需要异步,只需return 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>()
的测试中忽略它。