调用命令接口时异步测试场景失败
Async testing scenario fails when call made to command interface
我在 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()
,甚至在 SetSurveyContext
将 setter
设置为 3
.
之前
解决方法:
我们找到了在 TesterPage
中创建一个新的私有字段的解决方案,它应该包含在 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;
}
}
我在 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()
,甚至在 SetSurveyContext
将 setter
设置为 3
.
之前
解决方法:
我们找到了在 TesterPage
中创建一个新的私有字段的解决方案,它应该包含在 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;
}
}