我有一个第三方API IOS绑定,我试图使用TouchRunner
测试(更像是集成测试)。
一个示例API方法是这样的 -
_client.AuthenticateWithUsername(username, token,
() => { // Success Callback },
() => { // NoConnection Callback },
(obj) => { // Other Error Callback });
调用API时会关闭并在后台执行一些工作然后最终进行上面的回调之一,我想使用类似的东西来控制单元测试的流程
How can I unit test async methods on the UI Thread with Xamarin iOS TouchRunner
不幸的是,当我插入AutoResetEvent
代码时,TouchRunner
只是挂起并且永远不会返回到GUI。
我也试过用TaskCompletionSource
如下 -
public async Task<AuthResponse> AuthenticateUserAsync(string username, string password)
{
TaskCompletionSource<AuthResponse> tcs = new TaskCompletionSource<AuthResponse>();
AuthResponse response = new AuthResponse { Success = false };
LoginResponse loginResponse = await LoginUser(username, password);
_client.AuthenticateWithUsername(username, loginResponse.token,
() =>
{
response.Success = true;
Console.WriteLine("Auth");
tcs.SetResult(response);
},
() => { tcs.SetResult(response); },
obj => { tcs.SetResult(response); },
obj => { tcs.SetResult(response); });
return await tcs.Task;
}
[Test]
public async void AuthenticateUserAsyncTest()
{
var auth = await AuthenticateUserAsync(_username, _password);
Assert.IsTrue(auth.Success);
}
调试器逐步完成,直到返回等待tcs.Task
,但随后导致类似的HUNG跑步者。
我该如何解决悬挂发生的原因?
由于这不起作用,我接着使用这样的代码 -
_client.AuthenticateWithUsername(_username, loginResponse.token,
() =>
{
Assert.Pass("This crashes the runner");
Assert.True(true); // This DOES NOT!
},
() =>
{
// This will crash runner also
Assert.Fail("NoConnection");
},
(InvalidTokenError obj) =>
{
Assert.Fail("InvalidToken" + obj.Description);
},
(ClientError obj) =>
{
Assert.Fail("ClientError" + obj.Description);
});
正如您所看到的,流程最终(可理解),运行测试,运行客户端调用,测试结束方法完成,显示测试成功,然后回调返回并且断言被调用,这使应用程序崩溃,我们假设是因为跑步者已经完成了测试,为什么一个断言工作和其他我不知道的崩溃。
所以,
谢谢@Nkosi,这是一个很好的建议,我忘了在原始测试期间添加,当我使用异步任务运行代码而不是无效时,我从TouchRunner立即阻止,甚至没有添加除API调用之外的任何其他代码!我认为这是一个红旗,但使用async void“似乎”允许“标准”异步测试,所以我继续进行,然后在上面的循环中结束。
由于TouchRunner在很长一段时间内没有更新,我花了很多时间在论坛和堆栈中尝试各种建议之后使用XUnit重新创建测试项目。
其他一些有用的链接是 -
结果:我很高兴地说上面的所有代码现在都适用于TaskCompletionSource和AutoResetTask场景
我现在可以安全地测试基于事件的API :)
我只是想确保其他用户都知道这一点。谢谢你的帮助。
一个观察是测试应该是async Task
而不是async void
即
public async Task AuthenticateUserAsyncTest() {
//...code removed for brevity.
}
async void是一个火,忘记所以抛出的任何异常都不会在当前上下文中发生,因此它们不会被捕获。