c# - 调用命令接口(interface)时异步测试场景失败

标签 c# asynchronous testing xamarin icommand

我在 Xamarin 项目中测试 ICommand 场景时遇到问题。我已将逻辑提取到下面的演示中。

场景 N1 运行顺利,但我需要场景 N2 才能工作。场景 N2 的问题在于,一旦到达

await Task.Run(() => Task.Delay(1000)); 

它跳回测试方法 Assert,显然 SetSurveyContext(int x) 尚未执行。

最奇怪的是,如果我从应用程序内部的 Xamarin 框架运行此代码,一切正常,可能是因为我以错误的方式执行命令。

这个问题真的很纠结,我尝试了很多方法来运行命令,但都没有奏效。如果有人遇到同样的问题,请帮助。谢谢。

场景 1 - 工作

[Test]
public async Task NewSurvey_SendObjectWithOnlyDate_StaticSurveyResourceIdAndDateSet()
{
        var mvmTest = new TesterPage();
        await mvmTest.NewSurvey();
        Assert.That(mvmTest.setter, Is.EqualTo(3));
}

public partial class TesterPage : ContentPage
{
    public int setter = 0;

    public TesterPage()
    {
        InitializeComponent ();
    }

    public async Task NewSurvey()
    {
        await PostNewSurvey();
    }

    private async Task PostNewSurvey()
    {
        var response = await Another();
        SetSurveyContext(response);
    }

    private async Task<int> Another()
    {
       await Task.Run(() => Task.Delay(1000));
       return 3;
    }

    private void SetSurveyContext(int x)
    {
        setter = x;
    }
}

测试绿色,一切顺利。

场景 N2 - 失败

[Test]
public async Task NewSurvey_SendObjectWithOnlyDate_StaticSurveyResourceIdAndDateSet()
{
        var mvmTest = new TesterPage();
        mvmTest.NewSurveyCommand.Execute(null);
        Assert.That(mvmTest.setter, Is.EqualTo(3));
}

public partial class TesterPage : ContentPage
{
    public int setter = 0;

    public TesterPage ()
    {
        InitializeComponent ();
        NewSurveyCommand = new Command(async () => await NewSurvey());
    }

    public ICommand NewSurveyCommand { get; private set; }

    public async Task NewSurvey()
    {
        await PostNewSurvey();
    }

    private async Task PostNewSurvey()
    {
        var response = await Another();
        SetSurveyContext(response);
    }

    private async Task<int> Another()
    {
       await Task.Run(() => Task.Delay(1000));
       return 3;
    }

    private void SetSurveyContext(int x)
    {
        setter = x;
    }
}

最佳答案

因为我已经在聊天中与@YuriZolotarev 解决了这个问题,这里是我们为遇到它的其他人找到的解决方案:
问题:
当在 TesterPage.Another() 中调用 Task.Run() 时,主线程跳回到测试方法。它会立即执行 Assert.That(),甚至在 SetSurveyContextsetter 设置为 3 之前。
解决方案:
我们找到了在 TesterPage 中创建新私有(private)字段的解决方案,该字段应包含在 TesterPage.Another() 中启动的 Task。这个 Task 可以通过反射在测试方法中等待。一切可能看起来像这样:

[Test]
public async Task NewSurvey_SendObjectWithOnlyDate_StaticSurveyResourceIdAndDateSet()
{
    var mvmTest = new TesterPage();
    mvmTest.NewSurveyCommand.Execute(null);
    // Use Reflection to wait for the task
    (GetInstanceField(typeof(TesterPage), mvmTest, "runningTask") as Task).Wait();
    Assert.That(mvmTest.setter, Is.EqualTo(3));
}

// A helper method to simplify Reflection
internal static object GetInstanceField(Type type, object instance, string fieldName)
{
    BindingFlags bindFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic
    | BindingFlags.Static;
    FieldInfo field = type.GetField(fieldName, bindFlags);
    return field.GetValue(instance);
}

public partial class TesterPage : ContentPage
{
    public int setter = 0;
    private Task runningTask; // The field our Task object is saved in

    public TesterPage ()
    {
        InitializeComponent ();
        NewSurveyCommand = new Command(async () => await (runningTask = NewSurvey()));
    }

    public ICommand NewSurveyCommand { get; private set; }

    public async Task NewSurvey()
    {
        await PostNewSurvey();
    }

    private async Task PostNewSurvey()
    {
        var response = await Another();
        SetSurveyContext(response);
    }

    private async Task<int> Another()
    {
        await Task.Run(() => Task.Delay(1000));
        return 3;
    }

    private void SetSurveyContext(int x)
    {
        setter = x;
    }
}

关于c# - 调用命令接口(interface)时异步测试场景失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48009062/

相关文章:

c# - 以相同的方式打乱两个列表

c# - 为什么 ODBCConnection.State 不可靠?

angular - 如何在 Angular2 中测试包含(ng-content)?

c# - 我可以在 LINQ 中声明/使用一些变量吗?或者我可以更清楚地编写以下 LINQ 吗?

c# - 从 View 模型的构造函数调用异步方法

asynchronous - 如何在生成器中使用 await?

asynchronous - 有没有办法创建一个异步流生成器来产生重复调用函数的结果?

ruby-on-rails - NoMethodError:ActionMailer::TestCase 中 nil:NilClass 的未定义方法 'env'

unit-testing - 为从中读取的函数填充 os.Stdin

c# - .NET 的短信库