【问题标题】:Xamarin TouchRunner Hangs calling IOS 3rd Party BindingXamarin TouchRunner 挂起调用 IOS 3rd 方绑定
【发布时间】:2018-02-20 20:00:52
【问题描述】:

我有一个第 3 方 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);
    }

调试器正常执行直到返回 await 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);
     });

如您所见,流程结束(可以理解),运行测试,运行客户端调用,测试方法结束,显示测试成功,然后回调返回并调用断言,这会使应用程序崩溃,这我们假设是因为跑步者已经完成了测试,为什么一个断言有效而其他我不知道的崩溃。

所以,

  • 我的方法是否正确?
  • 3rd 方 API 中是否发生了某些事情会导致这些方法挂起?我该如何调试?

【问题讨论】:

  • 一个观察结果是测试应该是async Task 而不是async voidpublic async Task AuthenticateUserAsyncTest()

标签: xamarin xamarin.ios nunit


【解决方案1】:

感谢@Nkosi,这是一个很好的建议,我在最初的测试过程中忘记补充一点,当我使用 async Task 而不是 void 运行代码时,我从 TouchRunner 得到了一个即时块,甚至没有添加任何其他代码,除了API调用!我想这是一个危险信号,但使用 async void “似乎”允许“标准”异步测试,所以我取得了进展,然后进入了上面的循环。

由于 TouchRunner 已经很长时间没有更新了,所以在论坛和堆栈上尝试了各种建议之后,我才花时间使用 XUnit 重新创建测试项目。

其他一些有用的链接是 -

结果:我很高兴地说,以上所有代码现在都适用于 TaskCompletionSource 和 AutoResetTask 场景

我现在可以安全地测试基于事件的 API :)

我只是想确保其他用户知道这一点。 感谢您的帮助。

【讨论】:

    【解决方案2】:

    一个观察是测试应该是async Task而不是async void,即

    public async Task AuthenticateUserAsyncTest() {
        //...code removed for brevity.
    }
    

    async void 很容易被遗忘,因此抛出的任何异常都不会在当前上下文中发生,因此不会被捕获。

    参考Async/Await - Best Practices in Asynchronous Programming

    【讨论】:

      猜你喜欢
      • 2014-10-21
      • 2020-03-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多