Skip to content

Commit 9404e96

Browse files
committed
Initial commit
Signed-off-by: Lukáš Jech <[email protected]>
0 parents  commit 9404e96

File tree

9 files changed

+440
-0
lines changed

9 files changed

+440
-0
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.vs/*
2+
Output/*
3+
Cache/*
4+
Logs/*

Project.xml

764 Bytes
Binary file not shown.

Source/Assert.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
using System;
2+
3+
namespace FlaxEngine.UnitTesting
4+
{
5+
/// <summary>
6+
/// Special type of exception that is used to terminate the test case early <seealso cref="Assert.Pass"/>
7+
/// </summary>
8+
/// <seealso cref="System.Exception" />
9+
public class SuccessException : Exception { }
10+
11+
public static class Assert
12+
{
13+
public static void Pass() => throw new SuccessException();
14+
public static void Fail() => throw new Exception();
15+
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(); }
19+
20+
public static void True(bool a) { if (!a) throw new Exception(); }
21+
public static void False(bool a) { if (a) throw new Exception(); }
22+
}
23+
}

Source/Editor/TestRunner.cs

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
using FlaxEditor;
2+
using FlaxEditor.GUI;
3+
using System;
4+
using System.Collections.Generic;
5+
using System.Linq;
6+
using System.Reflection;
7+
8+
namespace FlaxEngine.UnitTesting.Editor
9+
{
10+
public class TestRunner : EditorPlugin
11+
{
12+
private static List<Type> suites = new List<Type>();
13+
private MainMenuButton mmBtn;
14+
15+
public override PluginDescription Description => new PluginDescription
16+
{
17+
Author = "Lukáš Jech",
18+
AuthorUrl ="https://lukas.jech.me",
19+
Category = "Unit Testing",
20+
Description = "Simple unit testing framework",
21+
IsAlpha = false,
22+
IsBeta = false,
23+
Name = "Simple Unit Testing",
24+
SupportedPlatforms = new PlatformType[] {PlatformType.Windows},
25+
Version = new Version(1,0),
26+
RepositoryUrl = "https://github.com/klukule/flax-ut"
27+
};
28+
29+
public override void InitializeEditor()
30+
{
31+
base.InitializeEditor();
32+
33+
mmBtn = Editor.UI.MainMenu.AddButton("Unit Tests");
34+
mmBtn.ContextMenu.AddButton("Run unit tests").Clicked += RunTests;
35+
36+
}
37+
38+
public override void Deinitialize()
39+
{
40+
base.Deinitialize();
41+
if (mmBtn != null)
42+
{
43+
mmBtn.Dispose();
44+
mmBtn = null;
45+
}
46+
}
47+
48+
private static void GatherTests()
49+
{
50+
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
51+
suites.Clear();
52+
foreach (var assembly in assemblies)
53+
foreach (var type in assembly.GetTypes())
54+
if (type.GetCustomAttributes<TestFixture>().Count() > 0)
55+
suites.Add(type);
56+
}
57+
58+
public static void RunTests()
59+
{
60+
GatherTests();
61+
62+
foreach (var suite in suites)
63+
{
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();
67+
68+
var instance = Activator.CreateInstance(suite);
69+
70+
setup?.Invoke(instance, null);
71+
72+
foreach (var testMethod in tests)
73+
{
74+
// Mitigates the AttributeNullException
75+
foreach (var test in testMethod.GetCustomAttributes<Test>())
76+
{
77+
bool failed = false;
78+
try
79+
{
80+
testMethod?.Invoke(instance, null);
81+
}
82+
catch (Exception e)
83+
{
84+
if(e.GetType() != typeof(SuccessException))
85+
failed = true;
86+
}
87+
finally
88+
{
89+
Debug.Log($"Test '{suite.Name} {testMethod.Name}' finished with " + (failed ? "Error" : "Success"));
90+
}
91+
}
92+
93+
var testCases = testMethod.GetCustomAttributes<TestCase>();
94+
int successCount = 0;
95+
foreach (var testCase in testCases)
96+
{
97+
bool failed = false;
98+
try
99+
{
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))
107+
failed = true;
108+
}
109+
finally
110+
{
111+
if (!failed)
112+
successCount++;
113+
}
114+
}
115+
116+
if(testCases.Count() > 0)
117+
Debug.Log($"Test '{suite.Name} {testMethod.Name}' finished with {successCount}/{testCases.Count()} successfull test cases.");
118+
}
119+
120+
disposer?.Invoke(instance, null);
121+
}
122+
}
123+
}
124+
}

Source/ExampleClass.cs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#if !FLAX_PLUGIN
2+
using FlaxEngine.UnitTesting;
3+
4+
namespace UnitTests
5+
{
6+
[TestFixture]
7+
internal class SimpleTests
8+
{
9+
[Test]
10+
public void SuccessTest()
11+
{
12+
// Do nothing for success
13+
}
14+
15+
[Test]
16+
public void ErrorTest()
17+
{
18+
Assert.True(null != null);
19+
}
20+
}
21+
22+
[TestFixture]
23+
internal class SetupTests
24+
{
25+
private object Tested = null;
26+
27+
[SetUp]
28+
public void Setup()
29+
{
30+
Tested = "Test";
31+
}
32+
33+
[Test]
34+
public void SetupTest()
35+
{
36+
Assert.AreEqual(Tested, "Test");
37+
}
38+
39+
[TearDown]
40+
public void Dispose()
41+
{
42+
}
43+
}
44+
45+
[TestFixture]
46+
internal class CaseTests
47+
{
48+
// Just a bunch of test cases :)
49+
[TestCase(0, 5)]
50+
[TestCase(1, 4)]
51+
[TestCase(2, 3)]
52+
[TestCase(3, 2)]
53+
[TestCase(4, 1)]
54+
[TestCase(5, 0)]
55+
public void TestCaseTest(int a, int b)
56+
{
57+
Assert.True(a + b == 5);
58+
}
59+
60+
[TestCase(0, 5, ExpectedResult = 5)]
61+
[TestCase(10, 5, ExpectedResult = 15)]
62+
public int ExpectedResultsTests(int a, int b)
63+
{
64+
return a + b;
65+
}
66+
}
67+
}
68+
#endif

Source/TestAttributes.cs

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
using System;
2+
3+
namespace FlaxEngine.UnitTesting
4+
{
5+
[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)]
6+
public class TestCase : Attribute
7+
{
8+
public readonly object[] Attributes;
9+
public object ExpectedResult { get; set; }
10+
public TestCase(object T1)
11+
{
12+
Attributes = new object[] { T1 };
13+
}
14+
15+
public TestCase(object T1, object T2)
16+
{
17+
Attributes = new object[] { T1, T2 };
18+
}
19+
20+
public TestCase(object T1, object T2, object T3)
21+
{
22+
Attributes = new object[] { T1, T2, T3 };
23+
}
24+
25+
public TestCase(object T1, object T2, object T3, object T4)
26+
{
27+
Attributes = new object[] { T1, T2, T3, T4 };
28+
}
29+
30+
public TestCase(object T1, object T2, object T3, object T4, object T5)
31+
{
32+
Attributes = new object[] { T1, T2, T3, T4, T5 };
33+
}
34+
35+
public TestCase(object T1, object T2, object T3, object T4, object T5, object T6)
36+
{
37+
Attributes = new object[] { T1, T2, T3, T4, T5, T6 };
38+
}
39+
40+
public TestCase(object T1, object T2, object T3, object T4, object T5, object T6, object T7)
41+
{
42+
Attributes = new object[] { T1, T2, T3, T4, T5, T6, T7 };
43+
}
44+
}
45+
46+
[AttributeUsage(AttributeTargets.Method)]
47+
public class Test : Attribute
48+
{
49+
50+
}
51+
52+
[AttributeUsage(AttributeTargets.Method)]
53+
public class SetUp : Attribute
54+
{
55+
}
56+
57+
[AttributeUsage(AttributeTargets.Method)]
58+
public class TearDown : Attribute
59+
{
60+
}
61+
62+
[AttributeUsage(AttributeTargets.Class)]
63+
public class TestFixture : Attribute
64+
{
65+
}
66+
}

UnitTests.Editor.csproj

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3+
<PropertyGroup>
4+
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
5+
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
6+
<ProjectTypeGuids>{BE633490-FBA4-41EB-80D4-EFA312592B8E};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
7+
<ProjectGuid>{313C9B90-1114-412F-8DB7-464CAD579BDD}</ProjectGuid>
8+
<OutputType>Library</OutputType>
9+
<AssemblyName>Assembly.Editor</AssemblyName>
10+
<FileAlignment>512</FileAlignment>
11+
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
12+
<CompilerResponseFile>
13+
</CompilerResponseFile>
14+
<RootNamespace>UnitTests</RootNamespace>
15+
</PropertyGroup>
16+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
17+
<DebugSymbols>true</DebugSymbols>
18+
<DebugType>portable</DebugType>
19+
<Optimize>false</Optimize>
20+
<OutputPath>Cache\bin\</OutputPath>
21+
<IntermediateOutputPath>Cache\obj\Debug\</IntermediateOutputPath>
22+
<ErrorReport>prompt</ErrorReport>
23+
<WarningLevel>4</WarningLevel>
24+
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
25+
<DefineConstants>DEBUG;FLAX_ASSERTIONS;TRACE;FLAX_0;FLAX_0_3;FLAX_0_3_6173;FLAX_EDITOR;FLAX_WINDOWS;FLAX_EDITOR_WIN</DefineConstants>
26+
<UseVSHostingProcess>false</UseVSHostingProcess>
27+
</PropertyGroup>
28+
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
29+
<DebugType>portable</DebugType>
30+
<Optimize>true</Optimize>
31+
<OutputPath>Cache\bin\</OutputPath>
32+
<IntermediateOutputPath>Cache\obj\Release\</IntermediateOutputPath>
33+
<ErrorReport>prompt</ErrorReport>
34+
<WarningLevel>4</WarningLevel>
35+
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
36+
<DefineConstants>TRACE;FLAX_0;FLAX_0_3;FLAX_0_3_6173;FLAX_EDITOR;FLAX_WINDOWS;FLAX_EDITOR_WIN</DefineConstants>
37+
<UseVSHostingProcess>false</UseVSHostingProcess>
38+
</PropertyGroup>
39+
<ItemGroup>
40+
<Reference Include="mscorlib" />
41+
<Reference Include="System" />
42+
<Reference Include="System.Xml" />
43+
<Reference Include="System.Core" />
44+
<Reference Include="FlaxEngine">
45+
<HintPath>Cache\Assemblies\Release\FlaxEngine.dll</HintPath>
46+
</Reference>
47+
<Reference Include="Newtonsoft.Json">
48+
<HintPath>Cache\Assemblies\Release\Newtonsoft.Json.dll</HintPath>
49+
</Reference>
50+
<Reference Include="FlaxEditor">
51+
<HintPath>Cache\Assemblies\Release\FlaxEditor.dll</HintPath>
52+
</Reference>
53+
</ItemGroup>
54+
<ItemGroup>
55+
<ProjectReference Include="UnitTests.csproj">
56+
<Project>{3C97D434-E00C-49D2-AE6E-F6FC095E27D6}</Project>
57+
<Name>UnitTests</Name>
58+
</ProjectReference>
59+
</ItemGroup>
60+
<ItemGroup>
61+
<Compile Include="Cache\AssemblyInfo.cs" />
62+
<Compile Include="Source\Editor\TestRunner.cs" />
63+
</ItemGroup>
64+
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
65+
</Project>

0 commit comments

Comments
 (0)