Skip to content

Commit 2e98e30

Browse files
authored
Merge pull request #1 from FlaxCommunityProjects/dev
Plugin Form
2 parents 9404e96 + 8fa7b38 commit 2e98e30

File tree

8 files changed

+162
-71
lines changed

8 files changed

+162
-71
lines changed

Content/GameSettings.json

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{
2+
"ID": "6888874e4229953ae4692194ef19ddf2",
3+
"TypeName": "FlaxEditor.Content.Settings.GameSettings",
4+
"EngineBuild": 6187,
5+
"Data": {
6+
"ProductName": "Simple Unit Testing",
7+
"FirstScene": "00000000000000000000000000000000"
8+
}
9+
}

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Unit Testing Plugin for the FlaxEngine
2+

Source/Assert.cs renamed to Source/Editor/Assert.cs

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,33 @@
11
using System;
22

3-
namespace FlaxEngine.UnitTesting
3+
namespace FlaxCommunity.UnitTesting.Editor
44
{
55
/// <summary>
66
/// Special type of exception that is used to terminate the test case early <seealso cref="Assert.Pass"/>
77
/// </summary>
88
/// <seealso cref="System.Exception" />
9-
public class SuccessException : Exception { }
9+
public class SuccessException : Exception
10+
{
11+
public SuccessException()
12+
{
13+
}
14+
15+
public SuccessException(string message) : base(message)
16+
{
17+
}
18+
19+
public SuccessException(string message, Exception innerException) : base(message, innerException)
20+
{
21+
}
22+
}
1023

1124
public static class Assert
1225
{
1326
public static void Pass() => throw new SuccessException();
1427
public static void Fail() => throw new Exception();
1528

16-
// TODO: use Equals instead of ==
17-
public static void AreEqual(object a, object b) { if (a != b) throw new Exception(); }
18-
public static void AreNotEqual(object a, object b) { if (a == b) throw new Exception(); }
29+
public static void AreEqual(object a, object b) { if (!Equals(a, b)) throw new Exception(); }
30+
public static void AreNotEqual(object a, object b) { if (Equals(a, b)) throw new Exception(); }
1931

2032
public static void True(bool a) { if (!a) throw new Exception(); }
2133
public static void False(bool a) { if (a) throw new Exception(); }

Source/ExampleClass.cs renamed to Source/Editor/ExampleClass.cs

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#if !FLAX_PLUGIN
2-
using FlaxEngine.UnitTesting;
2+
using FlaxCommunity.UnitTesting.Editor;
33

4-
namespace UnitTests
4+
namespace UnitTests.Editor
55
{
66
[TestFixture]
77
internal class SimpleTests
@@ -15,17 +15,24 @@ public void SuccessTest()
1515
[Test]
1616
public void ErrorTest()
1717
{
18-
Assert.True(null != null);
18+
Assert.True(1 != 1);
1919
}
2020
}
2121

2222
[TestFixture]
2323
internal class SetupTests
2424
{
2525
private object Tested = null;
26+
private object Database = null;
27+
28+
[OneTimeSetUp]
29+
public void Init()
30+
{
31+
Database = new object { };
32+
}
2633

2734
[SetUp]
28-
public void Setup()
35+
public void BeforeEach()
2936
{
3037
Tested = "Test";
3138
}
@@ -37,8 +44,13 @@ public void SetupTest()
3744
}
3845

3946
[TearDown]
47+
public void AfterEach()
48+
{
49+
}
50+
4051
public void Dispose()
4152
{
53+
Database = null;
4254
}
4355
}
4456

Source/TestAttributes.cs renamed to Source/Editor/TestAttributes.cs

Lines changed: 37 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
using System;
22

3-
namespace FlaxEngine.UnitTesting
3+
namespace FlaxCommunity.UnitTesting.Editor
44
{
5+
/// <summary>
6+
/// A test case
7+
/// </summary>
58
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
6-
public class TestCase : Attribute
9+
public sealed class TestCase : Attribute
710
{
811
public readonly object[] Attributes;
912
public object ExpectedResult { get; set; }
@@ -43,24 +46,52 @@ public TestCase(object T1, object T2, object T3, object T4, object T5, object T6
4346
}
4447
}
4548

49+
/// <summary>
50+
/// A single test
51+
/// </summary>
4652
[AttributeUsage(AttributeTargets.Method)]
47-
public class Test : Attribute
53+
public sealed class Test : Attribute
4854
{
4955

5056
}
5157

58+
/// <summary>
59+
/// Executed before every single test
60+
/// </summary>
5261
[AttributeUsage(AttributeTargets.Method)]
53-
public class SetUp : Attribute
62+
public sealed class SetUp : Attribute
5463
{
5564
}
5665

66+
/// <summary>
67+
/// Executed after every single test
68+
/// </summary>
5769
[AttributeUsage(AttributeTargets.Method)]
58-
public class TearDown : Attribute
70+
public sealed class TearDown : Attribute
5971
{
6072
}
6173

74+
/// <summary>
75+
/// Executed before all tests
76+
/// </summary>
77+
[AttributeUsage(AttributeTargets.Method)]
78+
public sealed class OneTimeSetUp : Attribute
79+
{
80+
}
81+
82+
/// <summary>
83+
/// Executed after all tests
84+
/// </summary>
85+
[AttributeUsage(AttributeTargets.Method)]
86+
public sealed class OneTimeTearDown : Attribute
87+
{
88+
}
89+
90+
/// <summary>
91+
/// Specifies a class as a unit test class
92+
/// </summary>
6293
[AttributeUsage(AttributeTargets.Class)]
63-
public class TestFixture : Attribute
94+
public sealed class TestFixture : Attribute
6495
{
6596
}
6697
}

Source/Editor/TestRunner.cs

Lines changed: 68 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,120 +1,145 @@
11
using FlaxEditor;
22
using FlaxEditor.GUI;
3+
using FlaxEngine;
34
using System;
45
using System.Collections.Generic;
56
using System.Linq;
67
using System.Reflection;
8+
using FlaxCommunity.UnitTesting;
79

8-
namespace FlaxEngine.UnitTesting.Editor
10+
namespace FlaxCommunity.UnitTesting.Editor
911
{
1012
public class TestRunner : EditorPlugin
1113
{
12-
private static List<Type> suites = new List<Type>();
13-
private MainMenuButton mmBtn;
14+
private static readonly List<Type> _suites = new List<Type>();
15+
private MainMenuButton _mmBtn;
1416

1517
public override PluginDescription Description => new PluginDescription
1618
{
1719
Author = "Lukáš Jech",
18-
AuthorUrl ="https://lukas.jech.me",
20+
AuthorUrl = "https://lukas.jech.me",
1921
Category = "Unit Testing",
2022
Description = "Simple unit testing framework",
2123
IsAlpha = false,
2224
IsBeta = false,
2325
Name = "Simple Unit Testing",
24-
SupportedPlatforms = new PlatformType[] {PlatformType.Windows},
25-
Version = new Version(1,0),
26-
RepositoryUrl = "https://github.com/klukule/flax-ut"
26+
SupportedPlatforms = new PlatformType[] { PlatformType.Windows },
27+
Version = new Version(1, 1),
28+
RepositoryUrl = "https://github.com/FlaxCommunityProjects/FlaxUnitTesting"
2729
};
28-
30+
2931
public override void InitializeEditor()
3032
{
3133
base.InitializeEditor();
3234

33-
mmBtn = Editor.UI.MainMenu.AddButton("Unit Tests");
34-
mmBtn.ContextMenu.AddButton("Run unit tests").Clicked += RunTests;
35+
_mmBtn = Editor.UI.MainMenu.AddButton("Unit Tests");
36+
_mmBtn.ContextMenu.AddButton("Run unit tests").Clicked += RunTests;
37+
FlaxEditor.Scripting.ScriptsBuilder.ScriptsReloadBegin += ScriptsBuilder_ScriptsReloadBegin;
38+
}
3539

40+
private void ScriptsBuilder_ScriptsReloadBegin()
41+
{
42+
// Clear type information as per warning https://docs.flaxengine.com/manual/scripting/plugins/index.html
43+
_suites.Clear();
3644
}
3745

3846
public override void Deinitialize()
3947
{
4048
base.Deinitialize();
41-
if (mmBtn != null)
49+
if (_mmBtn != null)
4250
{
43-
mmBtn.Dispose();
44-
mmBtn = null;
51+
_mmBtn.Dispose();
52+
_mmBtn = null;
4553
}
4654
}
4755

4856
private static void GatherTests()
4957
{
5058
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
51-
suites.Clear();
59+
_suites.Clear();
5260
foreach (var assembly in assemblies)
5361
foreach (var type in assembly.GetTypes())
5462
if (type.GetCustomAttributes<TestFixture>().Count() > 0)
55-
suites.Add(type);
63+
_suites.Add(type);
5664
}
5765

5866
public static void RunTests()
5967
{
6068
GatherTests();
6169

62-
foreach (var suite in suites)
70+
foreach (var suite in _suites)
6371
{
64-
var tests = suite.GetMethods().Where(m => m.GetCustomAttributes<TestCase>().Count() > 0 || m.GetCustomAttributes<Test>().Count() > 0).ToArray();
65-
var setup = suite.GetMethods().Where(m => m.GetCustomAttributes<SetUp>().Count() > 0).FirstOrDefault();
66-
var disposer = suite.GetMethods().Where(m => m.GetCustomAttributes<TearDown>().Count() > 0).FirstOrDefault();
72+
var suiteMethods = suite.GetMethods();
73+
74+
var tests = suiteMethods.Where(m => m.GetCustomAttributes<Test>().Count() > 0 || m.GetCustomAttributes<TestCase>().Count() > 0).ToArray();
75+
var setup = suiteMethods.Where(m => m.GetCustomAttributes<OneTimeSetUp>().Count() > 0).FirstOrDefault();
76+
var disposer = suiteMethods.Where(m => m.GetCustomAttributes<OneTimeTearDown>().Count() > 0).FirstOrDefault();
77+
var beforeEach = suiteMethods.Where(m => m.GetCustomAttributes<SetUp>().Count() > 0).FirstOrDefault();
78+
var afterEach = suiteMethods.Where(m => m.GetCustomAttributes<TearDown>().Count() > 0).FirstOrDefault();
6779

6880
var instance = Activator.CreateInstance(suite);
6981

7082
setup?.Invoke(instance, null);
7183

7284
foreach (var testMethod in tests)
7385
{
74-
// Mitigates the AttributeNullException
75-
foreach (var test in testMethod.GetCustomAttributes<Test>())
86+
if (testMethod.GetCustomAttributes<Test>().Count() > 0)
7687
{
7788
bool failed = false;
89+
beforeEach?.Invoke(instance, null);
7890
try
7991
{
8092
testMethod?.Invoke(instance, null);
8193
}
82-
catch (Exception e)
94+
catch (TargetInvocationException e)
8395
{
84-
if(e.GetType() != typeof(SuccessException))
96+
if (!(e.InnerException is SuccessException))
8597
failed = true;
8698
}
99+
catch (Exception e)
100+
{
101+
failed = true;
102+
}
87103
finally
88104
{
105+
afterEach?.Invoke(instance, null);
89106
Debug.Log($"Test '{suite.Name} {testMethod.Name}' finished with " + (failed ? "Error" : "Success"));
90107
}
91108
}
92-
93-
var testCases = testMethod.GetCustomAttributes<TestCase>();
94-
int successCount = 0;
95-
foreach (var testCase in testCases)
109+
else
96110
{
97-
bool failed = false;
98-
try
111+
var testCases = testMethod.GetCustomAttributes<TestCase>();
112+
int successCount = 0;
113+
foreach (var testCase in testCases)
99114
{
100-
var result = testMethod?.Invoke(instance, testCase.Attributes);
101-
if (testCase.ExpectedResult != null)
102-
failed = !testCase.ExpectedResult.Equals(result);
103-
}
104-
catch (Exception e)
105-
{
106-
if(e.GetType() != typeof(SuccessException))
115+
bool failed = false;
116+
beforeEach?.Invoke(instance, null);
117+
try
118+
{
119+
var result = testMethod?.Invoke(instance, testCase.Attributes);
120+
if (testCase.ExpectedResult != null)
121+
failed = !testCase.ExpectedResult.Equals(result);
122+
}
123+
catch (TargetInvocationException e)
124+
{
125+
if (!(e.InnerException is SuccessException))
126+
failed = true;
127+
}
128+
catch (Exception e)
129+
{
107130
failed = true;
131+
}
132+
finally
133+
{
134+
afterEach?.Invoke(instance, null);
135+
136+
if (!failed)
137+
successCount++;
138+
}
108139
}
109-
finally
110-
{
111-
if (!failed)
112-
successCount++;
113-
}
114-
}
115140

116-
if(testCases.Count() > 0)
117141
Debug.Log($"Test '{suite.Name} {testMethod.Name}' finished with {successCount}/{testCases.Count()} successfull test cases.");
142+
}
118143
}
119144

120145
disposer?.Invoke(instance, null);

0 commit comments

Comments
 (0)