Browse Source

Support SetUp and TearDown methods by NUnit

pull/11169/head
Max Katz 3 years ago
parent
commit
321bf26a0a
  1. 57
      src/Headless/Avalonia.Headless.NUnit/AvaloniaTestCommand.cs
  2. 48
      tests/Avalonia.Headless.UnitTests/InputTests.cs

57
src/Headless/Avalonia.Headless.NUnit/AvaloniaTestCommand.cs

@ -1,4 +1,6 @@
using System.Threading.Tasks;
using System;
using System.Reflection;
using System.Threading.Tasks;
using NUnit.Framework.Interfaces;
using NUnit.Framework.Internal;
using NUnit.Framework.Internal.Commands;
@ -9,6 +11,11 @@ internal class AvaloniaTestCommand : DelegatingTestCommand
{
private readonly HeadlessUnitTestSession _session;
private static FieldInfo s_beforeTest = typeof(BeforeAndAfterTestCommand)
.GetField("BeforeTest", BindingFlags.Instance | BindingFlags.NonPublic)!;
private static FieldInfo s_afterTest = typeof(BeforeAndAfterTestCommand)
.GetField("AfterTest", BindingFlags.Instance | BindingFlags.NonPublic)!;
public AvaloniaTestCommand(HeadlessUnitTestSession session, TestCommand innerCommand)
: base(innerCommand)
{
@ -23,25 +30,41 @@ internal class AvaloniaTestCommand : DelegatingTestCommand
// Unfortunately, NUnit has issues with custom synchronization contexts, which means we need to add some hacks to make it work.
private async Task<TestResult> ExecuteTestMethod(TestExecutionContext context)
{
var testMethod = innerCommand.Test.Method;
var methodInfo = testMethod!.MethodInfo;
var result = methodInfo.Invoke(context.TestObject, innerCommand.Test.Arguments);
// Only Task, non generic ValueTask are supported in async context. No ValueTask<> nor F# tasks.
if (result is Task task)
{
await task;
}
else if (result is ValueTask valueTask)
try
{
await valueTask;
}
if (innerCommand is BeforeAndAfterTestCommand beforeTestCommand)
{
(s_beforeTest.GetValue(beforeTestCommand) as Action<TestExecutionContext>)?.Invoke(context);
}
var testMethod = innerCommand.Test.Method;
var methodInfo = testMethod!.MethodInfo;
context.CurrentResult.SetResult(ResultState.Success);
var result = methodInfo.Invoke(context.TestObject, innerCommand.Test.Arguments);
// Only Task, non generic ValueTask are supported in async context. No ValueTask<> nor F# tasks.
if (result is Task task)
{
await task;
}
else if (result is ValueTask valueTask)
{
await valueTask;
}
if (context.CurrentResult.AssertionResults.Count > 0)
context.CurrentResult.RecordTestCompletion();
context.CurrentResult.SetResult(ResultState.Success);
return context.CurrentResult;
if (context.CurrentResult.AssertionResults.Count > 0)
context.CurrentResult.RecordTestCompletion();
return context.CurrentResult;
}
finally
{
if (innerCommand is BeforeAndAfterTestCommand beforeTestCommand
&& context.ExecutionStatus != TestExecutionStatus.AbortRequested)
{
(s_afterTest.GetValue(beforeTestCommand) as Action<TestExecutionContext>)?.Invoke(context);
}
}
}
}

48
tests/Avalonia.Headless.UnitTests/InputTests.cs

@ -1,3 +1,5 @@
using System;
using System.Reactive.Disposables;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Layout;
@ -6,7 +8,27 @@ using Avalonia.Threading;
namespace Avalonia.Headless.UnitTests;
public class InputTests
#if XUNIT
: IDisposable
#endif
{
private Window _window;
#if NUNIT
[SetUp]
public void SetUp()
#elif XUNIT
public InputTests()
#endif
{
Dispatcher.UIThread.VerifyAccess();
_window = new Window
{
Width = 100,
Height = 100
};
}
[AvaloniaFact]
public void Should_Click_Button_On_Window()
{
@ -18,18 +40,24 @@ public class InputTests
};
button.Click += (_, _) => buttonClicked = true;
_window.Content = button;
_window.Show();
var window = new Window
{
Width = 100,
Height = 100,
Content = button
};
window.Show();
window.MouseDown(new Point(50, 50), MouseButton.Left);
window.MouseUp(new Point(50, 50), MouseButton.Left);
_window.MouseDown(new Point(50, 50), MouseButton.Left);
_window.MouseUp(new Point(50, 50), MouseButton.Left);
Assert.True(buttonClicked);
}
#if NUNIT
[TearDown]
public void TearDown()
#elif XUNIT
public void Dispose()
#endif
{
Dispatcher.UIThread.VerifyAccess();
_window.Close();
}
}

Loading…
Cancel
Save