异步等待在测试中生成空异常
Async Await generating a null exception in testing
我对一些异步代码做了很多大量的修改,而且我一直在修补它足够长的时间以至于我需要第二只眼睛。
在单元测试中,我调用我的异步代码,然后验证它应该 return 的值。最终执行异步操作的对象被模拟。
单元测试:
public void GetCharactersAsync_ById_Test()
{
var charDictionary = TestHelper.GetCharactersIdDictionary(1);
var mockReq = new Mock<IRequester>();
mockReq.Setup(x => x.CreateGetRequestAsync<Dictionary<long, Character>>
(It.IsAny<string>())).ReturnsAsync(charDictionary);
var char1 = TestHelper.GetCharacter();
var api = GameObject.GetInstance(mockReq.Object);
var character = api.GetCharacterAsync(TestHelper.GetRegion(), (int)char.Id);
Assert.AreEqual(character.Result.Name, char1.Name);
}
GetCharacterAsync:
public async Task<Character> GetCharacterAsync(Region region, int charId)
{
var res = await requester.CreateGetRequestAsync<Task<Dictionary<long, Character>>>
(bld.BuildUrlForEndpoint("GetCharacter",
region, charId.ToString()));
var obj = res.Result.Values.FirstOrDefault();
return obj;
}
requester.CreateGetRequestAsync(虽然这应该被嘲笑而不重要):
public async Task<T> CreateGetRequestAsync<T>(string urlString)
{
return await this.GetResultAsyncDeserialized<T>(new HttpRequestMessage(HttpMethod.Get, urlString));
}
最后是 GetResultAsyncDeserialized(虽然这是模拟的,应该无关紧要):
protected async Task<T> GetResultAsyncDeserialized<T>(HttpRequestMessage request)
{
var result = string.Empty;
using (var response = await httpClient.GetAsync(request.RequestUri))
{
if (!response.IsSuccessStatusCode)
{
HandleRequestFailure(response.StatusCode);
}
using (var content = response.Content)
{
result = await content.ReadAsStringAsync();
}
}
return JsonConvert.DeserializeObject<T>(result);
}
我对异步的经验几乎为零,这段代码在结构上与旧的工作代码非常相似(我移动了一些东西,比如 JsonConvert 到底层,而它以前是在顶层) .事实上,主要的变化都在被嘲笑的水平上,不应该影响单元测试。单元测试与旧的几乎相同(删除了一些serialization/deserialization)。
Exception is a Null Reference Exception on GetCharacterAsync line:
var obj = res.Result.Values.FirstOrDefault();
你的 await requester.CreateGetRequestAsync<Task<Dictionary<long, Character>>>
是错误的,你不应该将 Task
传递给那个函数,方法签名应该是 await requester.CreateGetRequestAsync<Dictionary<long, Character>>
public async Task<Character> GetCharacterAsync(Region region, int charId)
{
var res = await requester.CreateGetRequestAsync<Dictionary<long, Character>>
(bld.BuildUrlForEndpoint("GetCharacter",
region, charId.ToString()));
var obj = res.Values.FirstOrDefault();
return obj;
}
你得到 null
的原因是 GetCharacterAsync
你打电话给 CreateGetRequestAsync<Task<Dictionary<long, Character>>>
但你的最小起订量设置为 mockReq.Setup(x => x.CreateGetRequestAsync<Dictionary<long, Character>>
P.S。作为旁注,你真的不应该在你的测试中做 character.Result.Name
,进行测试 return async Task
而不是 void
并等待 [=22= 的结果].几乎每个单元测试库(包括 visual studio 中内置的那个)现在都支持 async/await。
public async Task GetCharactersAsync_ById_Test()
{
var charDictionary = TestHelper.GetCharactersIdDictionary(1);
var mockReq = new Mock<IRequester>();
mockReq.Setup(x => x.CreateGetRequestAsync<Dictionary<long, Character>>
(It.IsAny<string>())).ReturnsAsync(charDictionary);
var char1 = TestHelper.GetCharacter();
var api = GameObject.GetInstance(mockReq.Object);
var character = await api.GetCharacterAsync(TestHelper.GetRegion(), (int)char.Id);
Assert.AreEqual(character.Name, char1.Name);
}
我对一些异步代码做了很多大量的修改,而且我一直在修补它足够长的时间以至于我需要第二只眼睛。
在单元测试中,我调用我的异步代码,然后验证它应该 return 的值。最终执行异步操作的对象被模拟。
单元测试:
public void GetCharactersAsync_ById_Test()
{
var charDictionary = TestHelper.GetCharactersIdDictionary(1);
var mockReq = new Mock<IRequester>();
mockReq.Setup(x => x.CreateGetRequestAsync<Dictionary<long, Character>>
(It.IsAny<string>())).ReturnsAsync(charDictionary);
var char1 = TestHelper.GetCharacter();
var api = GameObject.GetInstance(mockReq.Object);
var character = api.GetCharacterAsync(TestHelper.GetRegion(), (int)char.Id);
Assert.AreEqual(character.Result.Name, char1.Name);
}
GetCharacterAsync:
public async Task<Character> GetCharacterAsync(Region region, int charId)
{
var res = await requester.CreateGetRequestAsync<Task<Dictionary<long, Character>>>
(bld.BuildUrlForEndpoint("GetCharacter",
region, charId.ToString()));
var obj = res.Result.Values.FirstOrDefault();
return obj;
}
requester.CreateGetRequestAsync(虽然这应该被嘲笑而不重要):
public async Task<T> CreateGetRequestAsync<T>(string urlString)
{
return await this.GetResultAsyncDeserialized<T>(new HttpRequestMessage(HttpMethod.Get, urlString));
}
最后是 GetResultAsyncDeserialized(虽然这是模拟的,应该无关紧要):
protected async Task<T> GetResultAsyncDeserialized<T>(HttpRequestMessage request)
{
var result = string.Empty;
using (var response = await httpClient.GetAsync(request.RequestUri))
{
if (!response.IsSuccessStatusCode)
{
HandleRequestFailure(response.StatusCode);
}
using (var content = response.Content)
{
result = await content.ReadAsStringAsync();
}
}
return JsonConvert.DeserializeObject<T>(result);
}
我对异步的经验几乎为零,这段代码在结构上与旧的工作代码非常相似(我移动了一些东西,比如 JsonConvert 到底层,而它以前是在顶层) .事实上,主要的变化都在被嘲笑的水平上,不应该影响单元测试。单元测试与旧的几乎相同(删除了一些serialization/deserialization)。
Exception is a Null Reference Exception on GetCharacterAsync line:
var obj = res.Result.Values.FirstOrDefault();
你的 await requester.CreateGetRequestAsync<Task<Dictionary<long, Character>>>
是错误的,你不应该将 Task
传递给那个函数,方法签名应该是 await requester.CreateGetRequestAsync<Dictionary<long, Character>>
public async Task<Character> GetCharacterAsync(Region region, int charId)
{
var res = await requester.CreateGetRequestAsync<Dictionary<long, Character>>
(bld.BuildUrlForEndpoint("GetCharacter",
region, charId.ToString()));
var obj = res.Values.FirstOrDefault();
return obj;
}
你得到 null
的原因是 GetCharacterAsync
你打电话给 CreateGetRequestAsync<Task<Dictionary<long, Character>>>
但你的最小起订量设置为 mockReq.Setup(x => x.CreateGetRequestAsync<Dictionary<long, Character>>
P.S。作为旁注,你真的不应该在你的测试中做 character.Result.Name
,进行测试 return async Task
而不是 void
并等待 [=22= 的结果].几乎每个单元测试库(包括 visual studio 中内置的那个)现在都支持 async/await。
public async Task GetCharactersAsync_ById_Test()
{
var charDictionary = TestHelper.GetCharactersIdDictionary(1);
var mockReq = new Mock<IRequester>();
mockReq.Setup(x => x.CreateGetRequestAsync<Dictionary<long, Character>>
(It.IsAny<string>())).ReturnsAsync(charDictionary);
var char1 = TestHelper.GetCharacter();
var api = GameObject.GetInstance(mockReq.Object);
var character = await api.GetCharacterAsync(TestHelper.GetRegion(), (int)char.Id);
Assert.AreEqual(character.Name, char1.Name);
}