From 85f640fe4716772a121dde2cdcc16c6b25b76289 Mon Sep 17 00:00:00 2001 From: MikePuzanov Date: Mon, 6 Dec 2021 00:20:27 +0300 Subject: [PATCH 1/7] add attributes --- MyNUnit/MyNUnit/After.cs | 12 ++++++++++++ MyNUnit/MyNUnit/AfterClass.cs | 12 ++++++++++++ MyNUnit/MyNUnit/Before.cs | 12 ++++++++++++ MyNUnit/MyNUnit/BeforeClass.cs | 12 ++++++++++++ MyNUnit/MyNUnit/MyNUnit.cs | 18 ++++++++++++++++++ MyNUnit/MyNUnit/Test.cs | 16 ++++++++++++++++ 6 files changed, 82 insertions(+) create mode 100644 MyNUnit/MyNUnit/After.cs create mode 100644 MyNUnit/MyNUnit/AfterClass.cs create mode 100644 MyNUnit/MyNUnit/Before.cs create mode 100644 MyNUnit/MyNUnit/BeforeClass.cs create mode 100644 MyNUnit/MyNUnit/MyNUnit.cs create mode 100644 MyNUnit/MyNUnit/Test.cs diff --git a/MyNUnit/MyNUnit/After.cs b/MyNUnit/MyNUnit/After.cs new file mode 100644 index 0000000..25e8ed1 --- /dev/null +++ b/MyNUnit/MyNUnit/After.cs @@ -0,0 +1,12 @@ +using System; + +namespace MyNUnit +{ + public class After : Attribute + { + public After() + { + + } + } +} \ No newline at end of file diff --git a/MyNUnit/MyNUnit/AfterClass.cs b/MyNUnit/MyNUnit/AfterClass.cs new file mode 100644 index 0000000..f8e7cef --- /dev/null +++ b/MyNUnit/MyNUnit/AfterClass.cs @@ -0,0 +1,12 @@ +using System; + +namespace MyNUnit +{ + public class AfterClass : Attribute + { + public AfterClass() + { + + } + } +} \ No newline at end of file diff --git a/MyNUnit/MyNUnit/Before.cs b/MyNUnit/MyNUnit/Before.cs new file mode 100644 index 0000000..73343d3 --- /dev/null +++ b/MyNUnit/MyNUnit/Before.cs @@ -0,0 +1,12 @@ +using System; + +namespace MyNUnit +{ + public class Before : Attribute + { + public Before() + { + + } + } +} \ No newline at end of file diff --git a/MyNUnit/MyNUnit/BeforeClass.cs b/MyNUnit/MyNUnit/BeforeClass.cs new file mode 100644 index 0000000..187a930 --- /dev/null +++ b/MyNUnit/MyNUnit/BeforeClass.cs @@ -0,0 +1,12 @@ +using System; + +namespace MyNUnit +{ + public class BeforeClass : Attribute + { + public BeforeClass() + { + + } + } +} \ No newline at end of file diff --git a/MyNUnit/MyNUnit/MyNUnit.cs b/MyNUnit/MyNUnit/MyNUnit.cs new file mode 100644 index 0000000..b25fa61 --- /dev/null +++ b/MyNUnit/MyNUnit/MyNUnit.cs @@ -0,0 +1,18 @@ +using System.Collections.Generic; +using System.IO; +using System.Threading.Tasks; + +namespace MyNUnit +{ + public class MyNUnit + { + public void RunTests(string path) + { + var task = new Task>[Directory.GetFiles(path, "*.dll").Length]; + for (int i = 0; i < task.Length; i++) + { + + } + } + } +} \ No newline at end of file diff --git a/MyNUnit/MyNUnit/Test.cs b/MyNUnit/MyNUnit/Test.cs new file mode 100644 index 0000000..bf7111a --- /dev/null +++ b/MyNUnit/MyNUnit/Test.cs @@ -0,0 +1,16 @@ +using System; + +namespace MyNUnit +{ + public class Test : Attribute + { + public Type Expected { get; set; } + + public string Ignore { get; set; } + + public Test() + { + + } + } +} \ No newline at end of file From cff246cbffb1aab65c12128fc556266da46f2198 Mon Sep 17 00:00:00 2001 From: MikePuzanov Date: Tue, 14 Dec 2021 15:30:25 +0300 Subject: [PATCH 2/7] add files --- MyNUnit/ForTests/ForTests.csproj | 15 ++ MyNUnit/ForTests/Test1.cs | 78 +++++++++ MyNUnit/MyNUnit.Test/MyNUnit.Test.cs | 36 ++++ MyNUnit/MyNUnit.Test/MyNUnit.Test.csproj | 21 +++ MyNUnit/MyNUnit.sln | 28 ++++ MyNUnit/MyNUnit/.dockerignore | 25 +++ MyNUnit/MyNUnit/Dockerfile | 18 ++ MyNUnit/MyNUnit/MyNUnit.cs | 202 ++++++++++++++++++++++- MyNUnit/MyNUnit/MyNUnit.csproj | 9 + MyNUnit/MyNUnit/Program.cs | 12 ++ MyNUnit/MyNUnit/Test.cs | 5 +- 11 files changed, 442 insertions(+), 7 deletions(-) create mode 100644 MyNUnit/ForTests/ForTests.csproj create mode 100644 MyNUnit/ForTests/Test1.cs create mode 100644 MyNUnit/MyNUnit.Test/MyNUnit.Test.cs create mode 100644 MyNUnit/MyNUnit.Test/MyNUnit.Test.csproj create mode 100644 MyNUnit/MyNUnit.sln create mode 100644 MyNUnit/MyNUnit/.dockerignore create mode 100644 MyNUnit/MyNUnit/Dockerfile create mode 100644 MyNUnit/MyNUnit/MyNUnit.csproj create mode 100644 MyNUnit/MyNUnit/Program.cs diff --git a/MyNUnit/ForTests/ForTests.csproj b/MyNUnit/ForTests/ForTests.csproj new file mode 100644 index 0000000..de6c8de --- /dev/null +++ b/MyNUnit/ForTests/ForTests.csproj @@ -0,0 +1,15 @@ + + + + net5.0 + enable + enable + preview + ClassLibrary1 + + + + + + + diff --git a/MyNUnit/ForTests/Test1.cs b/MyNUnit/ForTests/Test1.cs new file mode 100644 index 0000000..61f4c91 --- /dev/null +++ b/MyNUnit/ForTests/Test1.cs @@ -0,0 +1,78 @@ +using System; +using MyNUnit; + +namespace ClassLibrary1 +{ + public class Test1 + { + private int nonStaticCounter = 0; + + [Before] + public void NonStaticIncrement() => nonStaticCounter++; + + [Test(null)] + public void TestWithoutExpected() + { + + } + + [Test(null, "yes")] + public void TestShouldBeIgnored() + { + + } + + [Test(typeof(ArgumentException))] + public void TestWithExpectedException() + { + throw new ArgumentException(); + } + + + [Test(null)] + public void TestBefore() + { + if (nonStaticCounter != 1) + { + throw new ArgumentException(); + } + } + + [Test(null)] + public void NullExpectedButThrowException() + { + throw new ArgumentException(); + } + + [Test(typeof(ArgumentException))] + public void ExceptionExpectedButWasNull() + { + + } + + [Test(typeof(ArgumentException))] + public void OneExceptionExpectedButWasAnother() + { + throw new AggregateException(); + } + + [BeforeClass] + public void NonStaticBeforeClass() + { + + } + + [AfterClass] + public static void ExceptionInAfterClass() + { + throw new AggregateException(); + } + + [After] + [Test(null)] + public void TestWithIncompatibleAttributes() + { + + } + } +} \ No newline at end of file diff --git a/MyNUnit/MyNUnit.Test/MyNUnit.Test.cs b/MyNUnit/MyNUnit.Test/MyNUnit.Test.cs new file mode 100644 index 0000000..1d8855c --- /dev/null +++ b/MyNUnit/MyNUnit.Test/MyNUnit.Test.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using MyNUnit; + +namespace MyNUnit.Test +{ + public class Tests + { + private MyNUnit myNUnit = new MyNUnit(); + private string[] answer = new string[] + { + "Проверка тестов из Test1", + "Метод NonStaticBeforeClass содержит атрибут BeforeClass, но не является статическим", + "Метод TestWithIncompatibleAttributes имеет два несовместимых атрибута", + "В методе ExceptionInAfterClass возникло исключение: System.AggregateException", + "Тест TestWithExpectedException пройден успешно", + "Тест TestWithoutExpected пройден успешно", + "Тест TestBefore пройден успешно", + "Тест ExceptionExpectedButWasNull не пройден: ожидалось исключения типа System.ArgumentException", + "Тест OneExceptionExpectedButWasAnother не пройден: ожидалось исключения типа System.ArgumentException, возникло System.AggregateException", + "Тест NullExpectedButThrowException не пройден: возникло исключение System.ArgumentException" + }; + + [NUnit.Framework.Test] + public void TestForMessages() + { + var result = myNUnit.RunTests("../../../../ForTests/bin/Debug/net5.0/"); + foreach (var m in result) + { + Assert.IsTrue(answer.Contains(m.Item1)); + } + } + } +} \ No newline at end of file diff --git a/MyNUnit/MyNUnit.Test/MyNUnit.Test.csproj b/MyNUnit/MyNUnit.Test/MyNUnit.Test.csproj new file mode 100644 index 0000000..e5b56da --- /dev/null +++ b/MyNUnit/MyNUnit.Test/MyNUnit.Test.csproj @@ -0,0 +1,21 @@ + + + + net5.0 + enable + + false + + + + + + + + + + + + + + diff --git a/MyNUnit/MyNUnit.sln b/MyNUnit/MyNUnit.sln new file mode 100644 index 0000000..d49a3c8 --- /dev/null +++ b/MyNUnit/MyNUnit.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyNUnit", "MyNUnit\MyNUnit.csproj", "{1DB5464C-6E66-40C9-87A3-6511DD33C324}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyNUnit.Test", "MyNUnit.Test\MyNUnit.Test.csproj", "{E9C716B6-D491-4B60-BA36-063C4902B355}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ForTests", "ForTests\ForTests.csproj", "{05442C5E-59D8-4BC3-805B-9FF732926D2B}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1DB5464C-6E66-40C9-87A3-6511DD33C324}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1DB5464C-6E66-40C9-87A3-6511DD33C324}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1DB5464C-6E66-40C9-87A3-6511DD33C324}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1DB5464C-6E66-40C9-87A3-6511DD33C324}.Release|Any CPU.Build.0 = Release|Any CPU + {E9C716B6-D491-4B60-BA36-063C4902B355}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E9C716B6-D491-4B60-BA36-063C4902B355}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E9C716B6-D491-4B60-BA36-063C4902B355}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E9C716B6-D491-4B60-BA36-063C4902B355}.Release|Any CPU.Build.0 = Release|Any CPU + {05442C5E-59D8-4BC3-805B-9FF732926D2B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {05442C5E-59D8-4BC3-805B-9FF732926D2B}.Debug|Any CPU.Build.0 = Debug|Any CPU + {05442C5E-59D8-4BC3-805B-9FF732926D2B}.Release|Any CPU.ActiveCfg = Release|Any CPU + {05442C5E-59D8-4BC3-805B-9FF732926D2B}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/MyNUnit/MyNUnit/.dockerignore b/MyNUnit/MyNUnit/.dockerignore new file mode 100644 index 0000000..cd967fc --- /dev/null +++ b/MyNUnit/MyNUnit/.dockerignore @@ -0,0 +1,25 @@ +**/.dockerignore +**/.env +**/.git +**/.gitignore +**/.project +**/.settings +**/.toolstarget +**/.vs +**/.vscode +**/.idea +**/*.*proj.user +**/*.dbmdl +**/*.jfm +**/azds.yaml +**/bin +**/charts +**/docker-compose* +**/Dockerfile* +**/node_modules +**/npm-debug.log +**/obj +**/secrets.dev.yaml +**/values.dev.yaml +LICENSE +README.md \ No newline at end of file diff --git a/MyNUnit/MyNUnit/Dockerfile b/MyNUnit/MyNUnit/Dockerfile new file mode 100644 index 0000000..0e93997 --- /dev/null +++ b/MyNUnit/MyNUnit/Dockerfile @@ -0,0 +1,18 @@ +FROM mcr.microsoft.com/dotnet/runtime:5.0 AS base +WORKDIR /app + +FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build +WORKDIR /src +COPY ["MyNUnit/MyNUnit.csproj", "MyNUnit/"] +RUN dotnet restore "MyNUnit/MyNUnit.csproj" +COPY . . +WORKDIR "/src/MyNUnit" +RUN dotnet build "MyNUnit.csproj" -c Release -o /app/build + +FROM build AS publish +RUN dotnet publish "MyNUnit.csproj" -c Release -o /app/publish + +FROM base AS final +WORKDIR /app +COPY --from=publish /app/publish . +ENTRYPOINT ["dotnet", "MyNUnit.dll"] diff --git a/MyNUnit/MyNUnit/MyNUnit.cs b/MyNUnit/MyNUnit/MyNUnit.cs index b25fa61..7f2510f 100644 --- a/MyNUnit/MyNUnit/MyNUnit.cs +++ b/MyNUnit/MyNUnit/MyNUnit.cs @@ -1,18 +1,210 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Diagnostics; using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.CompilerServices; using System.Threading.Tasks; namespace MyNUnit { public class MyNUnit { - public void RunTests(string path) + public (string, string)[] RunTests(string path) { - var task = new Task>[Directory.GetFiles(path, "*.dll").Length]; - for (int i = 0; i < task.Length; i++) + var dll = Directory.GetFiles(path, "*.dll"); + var tasks = new Task>[dll.Length]; + for (int i = 0; i < dll.Length; i++) { - + var localI = i; + tasks[i] = Task.Run(() => DoTestFromDll(dll[localI])); } + var infoAboutTests = new List<(string, string)>(); + for (int i = 0; i < tasks.Length; i++) + { + infoAboutTests = infoAboutTests.Union(tasks[i].Result).ToList(); + } + + if (infoAboutTests.Count == 0) + { + return new[] { ("По заданному пути не было найдено тестов", "") }; + } + return infoAboutTests.ToArray(); + } + + private List<(string, string)> DoTestFromDll(string dllPath) + { + var messages = new List<(string, string)>(); + var dll = Assembly.LoadFrom(dllPath); + var classes = dll.ExportedTypes.Where(t => t.IsClass); + foreach (Type t in classes) + { + var infoAboutTests = DoWorkInClass(t); + messages = messages.Union(infoAboutTests).ToList(); + } + return messages; + } + + private void RunMethodsWithAttributes(MethodInfo[] methodInfos, List<(string, string)> messagesForUser, object ClassIntstase) + { + foreach (var method in methodInfos) + { + try + { + method.Invoke(ClassIntstase, null); + } + catch (Exception e) + { + messagesForUser.Add(($"В методе {method.Name} возникло исключение: {e.InnerException.GetType()}", "")); + } + } + } + + private void AddMethod(Attribute[] attributes, MethodInfo method, List list) + { + if (attributes.Length != 0) + { + list.Add(method); + } + } + + private int CheckAttributesInMethod(Attribute[] attribute) + { + if (attribute.Length > 0) + { + return 1; + } + + return 0; + } + + private List<(string, string)> DoWorkInClass(Type classDll) + { + var after = new List(); + var before = new List(); + var beforeClass = new List(); + var afterClass = new List(); + var tests = new List(); + var messagesForUser = new List<(string, string)>(); + var methods = classDll.GetMethods(); + foreach (var method in methods) + { + var attributesTest = Attribute.GetCustomAttributes(method).Where(t => t.GetType() == typeof(Test)).ToArray(); + var attributesBefore = Attribute.GetCustomAttributes(method).Where(t => t.GetType() == typeof(Before)).ToArray(); + var attributesAfter = Attribute.GetCustomAttributes(method).Where(t => t.GetType() == typeof(After)).ToArray(); + var attributesBeforeClass = Attribute.GetCustomAttributes(method).Where(t => t.GetType() == typeof(BeforeClass)).ToArray(); + var attributesAfterClass = Attribute.GetCustomAttributes(method).Where(t => t.GetType() == typeof(AfterClass)).ToArray(); + var count = 0; + count += CheckAttributesInMethod(attributesTest); + count += CheckAttributesInMethod(attributesAfter); + count += CheckAttributesInMethod(attributesBefore); + count += CheckAttributesInMethod(attributesAfterClass); + count += CheckAttributesInMethod(attributesBeforeClass); + if (count > 1) + { + messagesForUser.Add(($"Метод {method.Name} имеет два несовместимых атрибута", "")); + continue; + } + AddMethod(attributesTest, method, tests); + AddMethod(attributesBefore, method, before); + AddMethod(attributesAfter, method, after); + if (attributesBeforeClass.Length != 0) + { + if (method.IsStatic) + { + beforeClass.Add(method); + } + else + { + messagesForUser.Add(($"Метод {method.Name} содержит атрибут BeforeClass, но не является статическим", "")); + } + } + if (attributesAfterClass.Length != 0) + { + if (method.IsStatic) + { + afterClass.Add(method); + } + else + { + messagesForUser.Add(($"Метод {method.Name} содержит атрибут AfterClass, но не является статическим", "")); + } + } + } + + if (tests.Count < 1) + { + return messagesForUser; + } + + messagesForUser.Add(($"Проверка тестов из {classDll.Name}", "")); + + RunMethodsWithAttributes(beforeClass.ToArray(), messagesForUser, null); + var tasks = new Task>[tests.Count]; + for (int i = 0; i < tests.Count; i++) + { + var test = tests[i]; + var user = messagesForUser; + tasks[i] = Task.Run(() => + { + var messagesFromCurrentTest = new List<(string, string)>(); + var attribute = (Test)Attribute.GetCustomAttribute(test, typeof(Test)); + if (attribute.Ignore != null) + { + return messagesFromCurrentTest; + } + object classInstance = Activator.CreateInstance(classDll); + RunMethodsWithAttributes(before.ToArray(), messagesFromCurrentTest, classInstance); + var message = ("", ""); + var watch = new Stopwatch(); + watch.Start(); + try + { + test.Invoke(classInstance, null); + } + catch (Exception exception) + { + watch.Stop(); + if (attribute.Expected == null) + { + message = ($"Тест {test.Name} не пройден: возникло исключение {exception.InnerException.GetType()}", $"Время: {watch.ElapsedMilliseconds} ms"); + } + else if (exception.InnerException.GetType() != attribute.Expected) + { + message = ($"Тест {test.Name} не пройден: ожидалось исключения типа {attribute.Expected}, возникло {exception.InnerException.GetType()}", $"Время: {watch.ElapsedMilliseconds} ms"); + } + else + { + message = ($"Тест {test.Name} пройден успешно", $"Время: {watch.ElapsedMilliseconds} ms"); + } + } + finally + { + watch.Stop(); + if (message.Item1 == "") + { + if (attribute.Expected == null) + { + message = ($"Тест {test.Name} пройден успешно", $"Время: {watch.ElapsedMilliseconds} ms"); + } + else + { + message = ($"Тест {test.Name} не пройден: ожидалось исключения типа {attribute.Expected}", $"Время: {watch.ElapsedMilliseconds} ms"); + } + } + } + user.Add(message); + RunMethodsWithAttributes(after.ToArray(), messagesFromCurrentTest, classInstance); + return messagesFromCurrentTest; + }); + } + RunMethodsWithAttributes(afterClass.ToArray(), messagesForUser, null); + foreach (var task in tasks) + { + messagesForUser = messagesForUser.Union(task.Result).ToList(); + } + return messagesForUser; } } } \ No newline at end of file diff --git a/MyNUnit/MyNUnit/MyNUnit.csproj b/MyNUnit/MyNUnit/MyNUnit.csproj new file mode 100644 index 0000000..a184b89 --- /dev/null +++ b/MyNUnit/MyNUnit/MyNUnit.csproj @@ -0,0 +1,9 @@ + + + + Exe + net5.0 + Windows + + + diff --git a/MyNUnit/MyNUnit/Program.cs b/MyNUnit/MyNUnit/Program.cs new file mode 100644 index 0000000..074c43b --- /dev/null +++ b/MyNUnit/MyNUnit/Program.cs @@ -0,0 +1,12 @@ +using System; + +namespace MyNUnit +{ + class Program + { + static void Main(string[] args) + { + + } + } +} \ No newline at end of file diff --git a/MyNUnit/MyNUnit/Test.cs b/MyNUnit/MyNUnit/Test.cs index bf7111a..f783a7d 100644 --- a/MyNUnit/MyNUnit/Test.cs +++ b/MyNUnit/MyNUnit/Test.cs @@ -8,9 +8,10 @@ public class Test : Attribute public string Ignore { get; set; } - public Test() + public Test(Type expected, string ignore = null) { - + Expected = expected; + Ignore = ignore; } } } \ No newline at end of file From 4b8db7e8f2df9249a298d176a8fde0217b2e33fa Mon Sep 17 00:00:00 2001 From: MikePuzanov Date: Mon, 28 Mar 2022 16:39:45 +0300 Subject: [PATCH 3/7] Rework MyNUnit --- MyNUnit/AttributesMyNunit/After.cs | 15 + MyNUnit/AttributesMyNunit/AfterClass.cs | 15 + .../AttributesMyNunit.csproj | 10 + MyNUnit/AttributesMyNunit/Before.cs | 15 + MyNUnit/AttributesMyNunit/BeforeClass.cs | 15 + MyNUnit/AttributesMyNunit/Test.cs | 20 ++ MyNUnit/ForTests/ForTests.csproj | 4 +- MyNUnit/ForTests/Test1.cs | 109 +++--- MyNUnit/MyNUnit.Test/MyNUnit.Test.cs | 48 ++- MyNUnit/MyNUnit.Test/MyNUnit.Test.csproj | 5 +- MyNUnit/MyNUnit.sln | 6 + MyNUnit/MyNUnit/.dockerignore | 25 -- MyNUnit/MyNUnit/After.cs | 12 - MyNUnit/MyNUnit/AfterClass.cs | 12 - MyNUnit/MyNUnit/Before.cs | 12 - MyNUnit/MyNUnit/BeforeClass.cs | 12 - MyNUnit/MyNUnit/Dockerfile | 18 - MyNUnit/MyNUnit/MyNUnit.cs | 312 ++++++++---------- MyNUnit/MyNUnit/MyNUnit.csproj | 7 +- MyNUnit/MyNUnit/Program.cs | 31 +- MyNUnit/MyNUnit/Test.cs | 17 - 21 files changed, 355 insertions(+), 365 deletions(-) create mode 100644 MyNUnit/AttributesMyNunit/After.cs create mode 100644 MyNUnit/AttributesMyNunit/AfterClass.cs create mode 100644 MyNUnit/AttributesMyNunit/AttributesMyNunit.csproj create mode 100644 MyNUnit/AttributesMyNunit/Before.cs create mode 100644 MyNUnit/AttributesMyNunit/BeforeClass.cs create mode 100644 MyNUnit/AttributesMyNunit/Test.cs delete mode 100644 MyNUnit/MyNUnit/.dockerignore delete mode 100644 MyNUnit/MyNUnit/After.cs delete mode 100644 MyNUnit/MyNUnit/AfterClass.cs delete mode 100644 MyNUnit/MyNUnit/Before.cs delete mode 100644 MyNUnit/MyNUnit/BeforeClass.cs delete mode 100644 MyNUnit/MyNUnit/Dockerfile delete mode 100644 MyNUnit/MyNUnit/Test.cs diff --git a/MyNUnit/AttributesMyNunit/After.cs b/MyNUnit/AttributesMyNunit/After.cs new file mode 100644 index 0000000..435747a --- /dev/null +++ b/MyNUnit/AttributesMyNunit/After.cs @@ -0,0 +1,15 @@ +namespace AttributesMyNUnit; + +using System; + +/// +/// Атрибут, которым обозначают методы, которые вызываются после каждого тестом +/// +[AttributeUsage(AttributeTargets.Method)] +public class After : Attribute +{ + public After() + { + + } +} \ No newline at end of file diff --git a/MyNUnit/AttributesMyNunit/AfterClass.cs b/MyNUnit/AttributesMyNunit/AfterClass.cs new file mode 100644 index 0000000..33da8ea --- /dev/null +++ b/MyNUnit/AttributesMyNunit/AfterClass.cs @@ -0,0 +1,15 @@ +namespace AttributesMyNUnit; + +using System; + +/// +/// Атрибут, которым обозначают методы, которые вызываются после тестов +/// +[AttributeUsage(AttributeTargets.Method)] +public class AfterClass : Attribute +{ + public AfterClass() + { + + } +} \ No newline at end of file diff --git a/MyNUnit/AttributesMyNunit/AttributesMyNunit.csproj b/MyNUnit/AttributesMyNunit/AttributesMyNunit.csproj new file mode 100644 index 0000000..8bf737c --- /dev/null +++ b/MyNUnit/AttributesMyNunit/AttributesMyNunit.csproj @@ -0,0 +1,10 @@ + + + + net6.0 + enable + enable + Attributes + + + diff --git a/MyNUnit/AttributesMyNunit/Before.cs b/MyNUnit/AttributesMyNunit/Before.cs new file mode 100644 index 0000000..2194a2d --- /dev/null +++ b/MyNUnit/AttributesMyNunit/Before.cs @@ -0,0 +1,15 @@ +namespace AttributesMyNUnit; + +using System; + +/// +/// Атрибут, которым обозначают методы, которые вызываются перед каждым тестом +/// +[AttributeUsage(AttributeTargets.Method)] +public class Before : Attribute +{ + public Before() + { + + } +} \ No newline at end of file diff --git a/MyNUnit/AttributesMyNunit/BeforeClass.cs b/MyNUnit/AttributesMyNunit/BeforeClass.cs new file mode 100644 index 0000000..4b7393c --- /dev/null +++ b/MyNUnit/AttributesMyNunit/BeforeClass.cs @@ -0,0 +1,15 @@ +namespace AttributesMyNUnit; + +using System; + +/// +/// Атрибут, которым обозначают методы, которые вызываются перед тестами +/// +[AttributeUsage(AttributeTargets.Method)] +public class BeforeClass : Attribute +{ + public BeforeClass() + { + + } +} \ No newline at end of file diff --git a/MyNUnit/AttributesMyNunit/Test.cs b/MyNUnit/AttributesMyNunit/Test.cs new file mode 100644 index 0000000..48a9e9a --- /dev/null +++ b/MyNUnit/AttributesMyNunit/Test.cs @@ -0,0 +1,20 @@ +namespace AttributesMyNUnit; + +using System; + +/// +/// Атрибут, которым обозначают методы, которые являются тестами +/// +[AttributeUsage(AttributeTargets.Method)] +public class Test : Attribute +{ + public Type Expected { get; set; } + + public string Ignore { get; set; } + + public Test(Type expected, string ignore = null) + { + Expected = expected; + Ignore = ignore; + } +} \ No newline at end of file diff --git a/MyNUnit/ForTests/ForTests.csproj b/MyNUnit/ForTests/ForTests.csproj index de6c8de..f532cbb 100644 --- a/MyNUnit/ForTests/ForTests.csproj +++ b/MyNUnit/ForTests/ForTests.csproj @@ -1,10 +1,10 @@ - net5.0 + net6.0 enable enable - preview + 10 ClassLibrary1 diff --git a/MyNUnit/ForTests/Test1.cs b/MyNUnit/ForTests/Test1.cs index 61f4c91..4a666c2 100644 --- a/MyNUnit/ForTests/Test1.cs +++ b/MyNUnit/ForTests/Test1.cs @@ -1,78 +1,77 @@ -using System; -using MyNUnit; +namespace ForTests; -namespace ClassLibrary1 +using System; +using AttributesMyNUnit; + +public class Test1 { - public class Test1 - { - private int nonStaticCounter = 0; + private int nonStaticCounter = 0; - [Before] - public void NonStaticIncrement() => nonStaticCounter++; + [Before] + public void NonStaticIncrement() => nonStaticCounter++; - [Test(null)] - public void TestWithoutExpected() - { + [Test(null)] + public void TestWithoutExpected() + { - } + } - [Test(null, "yes")] - public void TestShouldBeIgnored() - { + [Test(null, "yes")] + public void TestShouldBeIgnored() + { - } + } - [Test(typeof(ArgumentException))] - public void TestWithExpectedException() - { - throw new ArgumentException(); - } + [Test(typeof(ArgumentException))] + public void TestWithExpectedException() + { + throw new ArgumentException(); + } - [Test(null)] - public void TestBefore() - { - if (nonStaticCounter != 1) - { - throw new ArgumentException(); - } - } - - [Test(null)] - public void NullExpectedButThrowException() + [Test(null)] + public void TestBefore() + { + if (nonStaticCounter != 1) { throw new ArgumentException(); } + } + + [Test(null)] + public void NullExpectedButThrowException() + { + throw new ArgumentException(); + } - [Test(typeof(ArgumentException))] - public void ExceptionExpectedButWasNull() - { + [Test(typeof(ArgumentException))] + public void ExceptionExpectedButWasNull() + { - } + } - [Test(typeof(ArgumentException))] - public void OneExceptionExpectedButWasAnother() - { - throw new AggregateException(); - } + [Test(typeof(ArgumentException))] + public void OneExceptionExpectedButWasAnother() + { + throw new AggregateException(); + } - [BeforeClass] - public void NonStaticBeforeClass() - { + [BeforeClass] + public void NonStaticBeforeClass() + { - } + } - [AfterClass] - public static void ExceptionInAfterClass() - { - throw new AggregateException(); - } + [AfterClass] + public static void ExceptionInAfterClass() + { + throw new AggregateException(); + } - [After] - [Test(null)] - public void TestWithIncompatibleAttributes() - { + [After] + [Test(null)] + public void TestWithIncompatibleAttributes() + { - } } } \ No newline at end of file diff --git a/MyNUnit/MyNUnit.Test/MyNUnit.Test.cs b/MyNUnit/MyNUnit.Test/MyNUnit.Test.cs index 1d8855c..4ea0bfb 100644 --- a/MyNUnit/MyNUnit.Test/MyNUnit.Test.cs +++ b/MyNUnit/MyNUnit.Test/MyNUnit.Test.cs @@ -1,36 +1,32 @@ -using System; -using System.Collections.Generic; +namespace MyNUnit.Test; + using System.Linq; using NUnit.Framework; -using MyNUnit; -namespace MyNUnit.Test +public class Tests { - public class Tests + private readonly MyNUnit myNUnit = new MyNUnit(); + private readonly string[] answer = new string[] { - private MyNUnit myNUnit = new MyNUnit(); - private string[] answer = new string[] - { - "Проверка тестов из Test1", - "Метод NonStaticBeforeClass содержит атрибут BeforeClass, но не является статическим", - "Метод TestWithIncompatibleAttributes имеет два несовместимых атрибута", - "В методе ExceptionInAfterClass возникло исключение: System.AggregateException", - "Тест TestWithExpectedException пройден успешно", - "Тест TestWithoutExpected пройден успешно", - "Тест TestBefore пройден успешно", - "Тест ExceptionExpectedButWasNull не пройден: ожидалось исключения типа System.ArgumentException", - "Тест OneExceptionExpectedButWasAnother не пройден: ожидалось исключения типа System.ArgumentException, возникло System.AggregateException", - "Тест NullExpectedButThrowException не пройден: возникло исключение System.ArgumentException" - }; + "Проверка тестов из Test1", + "Метод NonStaticBeforeClass содержит атрибут BeforeClass, но не является статическим", + "Метод TestWithIncompatibleAttributes имеет два несовместимых атрибута", + "В методе ExceptionInAfterClass возникло исключение: System.AggregateException", + "Тест TestWithExpectedException пройден успешно", + "Тест TestWithoutExpected пройден успешно", + "Тест TestBefore пройден успешно", + "Тест ExceptionExpectedButWasNull не пройден: ожидалось исключения типа System.ArgumentException", + "Тест OneExceptionExpectedButWasAnother не пройден: ожидалось исключения типа System.ArgumentException, возникло System.AggregateException", + "Тест NullExpectedButThrowException не пройден: возникло исключение System.ArgumentException" + }; - [NUnit.Framework.Test] - public void TestForMessages() + [NUnit.Framework.Test] + public void TestForMessages() + { + var result = myNUnit.RunTests("../../../../ForTests/bin/Debug/net5.0/"); + foreach (var m in result) { - var result = myNUnit.RunTests("../../../../ForTests/bin/Debug/net5.0/"); - foreach (var m in result) - { - Assert.IsTrue(answer.Contains(m.Item1)); - } + Assert.IsTrue(answer.Contains(m.Item1)); } } } \ No newline at end of file diff --git a/MyNUnit/MyNUnit.Test/MyNUnit.Test.csproj b/MyNUnit/MyNUnit.Test/MyNUnit.Test.csproj index e5b56da..6cd73e0 100644 --- a/MyNUnit/MyNUnit.Test/MyNUnit.Test.csproj +++ b/MyNUnit/MyNUnit.Test/MyNUnit.Test.csproj @@ -1,10 +1,12 @@ - net5.0 + net6.0 enable false + + 10 @@ -15,6 +17,7 @@ + diff --git a/MyNUnit/MyNUnit.sln b/MyNUnit/MyNUnit.sln index d49a3c8..f460980 100644 --- a/MyNUnit/MyNUnit.sln +++ b/MyNUnit/MyNUnit.sln @@ -6,6 +6,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyNUnit.Test", "MyNUnit.Tes EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ForTests", "ForTests\ForTests.csproj", "{05442C5E-59D8-4BC3-805B-9FF732926D2B}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AttributesMyNunit", "AttributesMyNunit\AttributesMyNunit.csproj", "{9EE0AFA0-1759-431B-9810-E49A29F36499}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -24,5 +26,9 @@ Global {05442C5E-59D8-4BC3-805B-9FF732926D2B}.Debug|Any CPU.Build.0 = Debug|Any CPU {05442C5E-59D8-4BC3-805B-9FF732926D2B}.Release|Any CPU.ActiveCfg = Release|Any CPU {05442C5E-59D8-4BC3-805B-9FF732926D2B}.Release|Any CPU.Build.0 = Release|Any CPU + {9EE0AFA0-1759-431B-9810-E49A29F36499}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9EE0AFA0-1759-431B-9810-E49A29F36499}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9EE0AFA0-1759-431B-9810-E49A29F36499}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9EE0AFA0-1759-431B-9810-E49A29F36499}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection EndGlobal diff --git a/MyNUnit/MyNUnit/.dockerignore b/MyNUnit/MyNUnit/.dockerignore deleted file mode 100644 index cd967fc..0000000 --- a/MyNUnit/MyNUnit/.dockerignore +++ /dev/null @@ -1,25 +0,0 @@ -**/.dockerignore -**/.env -**/.git -**/.gitignore -**/.project -**/.settings -**/.toolstarget -**/.vs -**/.vscode -**/.idea -**/*.*proj.user -**/*.dbmdl -**/*.jfm -**/azds.yaml -**/bin -**/charts -**/docker-compose* -**/Dockerfile* -**/node_modules -**/npm-debug.log -**/obj -**/secrets.dev.yaml -**/values.dev.yaml -LICENSE -README.md \ No newline at end of file diff --git a/MyNUnit/MyNUnit/After.cs b/MyNUnit/MyNUnit/After.cs deleted file mode 100644 index 25e8ed1..0000000 --- a/MyNUnit/MyNUnit/After.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace MyNUnit -{ - public class After : Attribute - { - public After() - { - - } - } -} \ No newline at end of file diff --git a/MyNUnit/MyNUnit/AfterClass.cs b/MyNUnit/MyNUnit/AfterClass.cs deleted file mode 100644 index f8e7cef..0000000 --- a/MyNUnit/MyNUnit/AfterClass.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace MyNUnit -{ - public class AfterClass : Attribute - { - public AfterClass() - { - - } - } -} \ No newline at end of file diff --git a/MyNUnit/MyNUnit/Before.cs b/MyNUnit/MyNUnit/Before.cs deleted file mode 100644 index 73343d3..0000000 --- a/MyNUnit/MyNUnit/Before.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace MyNUnit -{ - public class Before : Attribute - { - public Before() - { - - } - } -} \ No newline at end of file diff --git a/MyNUnit/MyNUnit/BeforeClass.cs b/MyNUnit/MyNUnit/BeforeClass.cs deleted file mode 100644 index 187a930..0000000 --- a/MyNUnit/MyNUnit/BeforeClass.cs +++ /dev/null @@ -1,12 +0,0 @@ -using System; - -namespace MyNUnit -{ - public class BeforeClass : Attribute - { - public BeforeClass() - { - - } - } -} \ No newline at end of file diff --git a/MyNUnit/MyNUnit/Dockerfile b/MyNUnit/MyNUnit/Dockerfile deleted file mode 100644 index 0e93997..0000000 --- a/MyNUnit/MyNUnit/Dockerfile +++ /dev/null @@ -1,18 +0,0 @@ -FROM mcr.microsoft.com/dotnet/runtime:5.0 AS base -WORKDIR /app - -FROM mcr.microsoft.com/dotnet/sdk:5.0 AS build -WORKDIR /src -COPY ["MyNUnit/MyNUnit.csproj", "MyNUnit/"] -RUN dotnet restore "MyNUnit/MyNUnit.csproj" -COPY . . -WORKDIR "/src/MyNUnit" -RUN dotnet build "MyNUnit.csproj" -c Release -o /app/build - -FROM build AS publish -RUN dotnet publish "MyNUnit.csproj" -c Release -o /app/publish - -FROM base AS final -WORKDIR /app -COPY --from=publish /app/publish . -ENTRYPOINT ["dotnet", "MyNUnit.dll"] diff --git a/MyNUnit/MyNUnit/MyNUnit.cs b/MyNUnit/MyNUnit/MyNUnit.cs index 7f2510f..7b3da01 100644 --- a/MyNUnit/MyNUnit/MyNUnit.cs +++ b/MyNUnit/MyNUnit/MyNUnit.cs @@ -1,210 +1,188 @@ -using System; +namespace MyNUnit; + +using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; -using System.Runtime.CompilerServices; using System.Threading.Tasks; +using AttributesMyNUnit; -namespace MyNUnit +/// +/// Класс MyNUnit для запуска и проверки тестов +/// +public class MyNUnit { - public class MyNUnit + /// + /// запуск тестов из .dll + /// + /// путь до .dll + /// Кортеж из (названия теста, результат о нем) + public (string, string)[] RunTests(string path) + { + var dlls = Directory.GetFiles(path, "*.dll"); + var tasks = new Task>[dlls.Length]; + var message = new List<(string, string)>(); + Parallel.ForEach(dlls,dll => DoTestFromDll(dll, message)); + return message.ToArray(); + } + + private void DoTestFromDll(string dllPath, List<(string, string)> message) + { + var dll = Assembly.LoadFrom(dllPath); + var classes = dll.ExportedTypes.Where(t => t.IsClass); + Parallel.ForEach(classes, c => DoWorkInClass(c, message)); + } + + private void DoWorkInClass(Type classFromDll, List<(string, string)> messagesForUser) { - public (string, string)[] RunTests(string path) + var after = new List(); + var before = new List(); + var beforeClass = new List(); + var afterClass = new List(); + var tests = new List(); + var methods = classFromDll.GetMethods(); + Parallel.ForEach(methods, method => GetAttributesAndDoBeforeAndAfterClass(method, after, before, beforeClass, afterClass, tests, messagesForUser)); + Parallel.ForEach(beforeClass, method => RunMethodsWithAttributes(method, messagesForUser, null)); + + if (tests.Count < 1) { - var dll = Directory.GetFiles(path, "*.dll"); - var tasks = new Task>[dll.Length]; - for (int i = 0; i < dll.Length; i++) - { - var localI = i; - tasks[i] = Task.Run(() => DoTestFromDll(dll[localI])); - } - var infoAboutTests = new List<(string, string)>(); - for (int i = 0; i < tasks.Length; i++) + return; + } + messagesForUser.Add(($"Проверка тестов из {classFromDll.Name}", "")); + + Parallel.ForEach(tests, test => DoTest(test, messagesForUser, before, after, classFromDll)); + Parallel.ForEach(afterClass, method => RunMethodsWithAttributes(method, messagesForUser, null)); + } + + private void DoTest(MethodInfo test, List<(string, string)> messagesFromCurrentTest, List before, + List after, Type classDll) + { + var attribute = (Test)Attribute.GetCustomAttribute(test, typeof(Test)); + if (attribute.Ignore != null) + { + return; + } + object classInstance = Activator.CreateInstance(classDll); + Parallel.ForEach(before, method => RunMethodsWithAttributes(method, messagesFromCurrentTest, classInstance)); + var message = ("", ""); + var watch = new Stopwatch(); + watch.Start(); + try + { + test.Invoke(classInstance, null); + } + catch (Exception exception) + { + watch.Stop(); + if (attribute.Expected == null) { - infoAboutTests = infoAboutTests.Union(tasks[i].Result).ToList(); + message = ($"Тест {test.Name} не пройден: возникло исключение {exception.InnerException.GetType()}", $"Время: {watch.ElapsedMilliseconds} ms"); } - - if (infoAboutTests.Count == 0) + else if (exception.InnerException.GetType() != attribute.Expected) { - return new[] { ("По заданному пути не было найдено тестов", "") }; + message = ($"Тест {test.Name} не пройден: ожидалось исключения типа {attribute.Expected}, возникло {exception.InnerException.GetType()}", $"Время: {watch.ElapsedMilliseconds} ms"); } - return infoAboutTests.ToArray(); - } - - private List<(string, string)> DoTestFromDll(string dllPath) - { - var messages = new List<(string, string)>(); - var dll = Assembly.LoadFrom(dllPath); - var classes = dll.ExportedTypes.Where(t => t.IsClass); - foreach (Type t in classes) + else { - var infoAboutTests = DoWorkInClass(t); - messages = messages.Union(infoAboutTests).ToList(); + message = ($"Тест {test.Name} пройден успешно", $"Время: {watch.ElapsedMilliseconds} ms"); } - return messages; } - - private void RunMethodsWithAttributes(MethodInfo[] methodInfos, List<(string, string)> messagesForUser, object ClassIntstase) + finally { - foreach (var method in methodInfos) + watch.Stop(); + if (message.Item1 == "") { - try + if (attribute.Expected == null) { - method.Invoke(ClassIntstase, null); + message = ($"Тест {test.Name} пройден успешно", $"Время: {watch.ElapsedMilliseconds} ms"); } - catch (Exception e) + else { - messagesForUser.Add(($"В методе {method.Name} возникло исключение: {e.InnerException.GetType()}", "")); + message = ($"Тест {test.Name} не пройден: ожидалось исключения типа {attribute.Expected}", $"Время: {watch.ElapsedMilliseconds} ms"); } } } + messagesFromCurrentTest.Add(message); + + Parallel.ForEach(after, method => RunMethodsWithAttributes(method, messagesFromCurrentTest, classInstance)); + } - private void AddMethod(Attribute[] attributes, MethodInfo method, List list) + private void AddMethod(Attribute[] attributes, MethodInfo method, List list) + { + if (attributes.Length != 0) { - if (attributes.Length != 0) - { - list.Add(method); - } + list.Add(method); } + } - private int CheckAttributesInMethod(Attribute[] attribute) + private int CheckAttributesInMethod(Attribute[] attribute) + { + if (attribute.Length > 0) { - if (attribute.Length > 0) - { - return 1; - } + return 1; + } - return 0; + return 0; + } + + private void RunMethodsWithAttributes(MethodInfo method, List<(string, string)> messagesForUser, object ClassIntstase) + { + try + { + method.Invoke(ClassIntstase, null); + } + catch (Exception e) + { + messagesForUser.Add(($"В методе {method.Name} возникло исключение: {e.InnerException.GetType()}", "")); } + } - private List<(string, string)> DoWorkInClass(Type classDll) + private void GetAttributesAndDoBeforeAndAfterClass(MethodInfo method, List after, + List before, List beforeClass, List afterClass, List tests, + List<(string, string)> messagesForUser) + { + var attributesTest = Attribute.GetCustomAttributes(method).Where(t => t.GetType() == typeof(Test)).ToArray(); + var attributesBefore = Attribute.GetCustomAttributes(method).Where(t => t.GetType() == typeof(Before)).ToArray(); + var attributesAfter = Attribute.GetCustomAttributes(method).Where(t => t.GetType() == typeof(After)).ToArray(); + var attributesBeforeClass = Attribute.GetCustomAttributes(method).Where(t => t.GetType() == typeof(BeforeClass)).ToArray(); + var attributesAfterClass = Attribute.GetCustomAttributes(method).Where(t => t.GetType() == typeof(AfterClass)).ToArray(); + var count = 0; + count += CheckAttributesInMethod(attributesTest); + count += CheckAttributesInMethod(attributesAfter); + count += CheckAttributesInMethod(attributesBefore); + count += CheckAttributesInMethod(attributesAfterClass); + count += CheckAttributesInMethod(attributesBeforeClass); + if (count > 1) { - var after = new List(); - var before = new List(); - var beforeClass = new List(); - var afterClass = new List(); - var tests = new List(); - var messagesForUser = new List<(string, string)>(); - var methods = classDll.GetMethods(); - foreach (var method in methods) - { - var attributesTest = Attribute.GetCustomAttributes(method).Where(t => t.GetType() == typeof(Test)).ToArray(); - var attributesBefore = Attribute.GetCustomAttributes(method).Where(t => t.GetType() == typeof(Before)).ToArray(); - var attributesAfter = Attribute.GetCustomAttributes(method).Where(t => t.GetType() == typeof(After)).ToArray(); - var attributesBeforeClass = Attribute.GetCustomAttributes(method).Where(t => t.GetType() == typeof(BeforeClass)).ToArray(); - var attributesAfterClass = Attribute.GetCustomAttributes(method).Where(t => t.GetType() == typeof(AfterClass)).ToArray(); - var count = 0; - count += CheckAttributesInMethod(attributesTest); - count += CheckAttributesInMethod(attributesAfter); - count += CheckAttributesInMethod(attributesBefore); - count += CheckAttributesInMethod(attributesAfterClass); - count += CheckAttributesInMethod(attributesBeforeClass); - if (count > 1) - { - messagesForUser.Add(($"Метод {method.Name} имеет два несовместимых атрибута", "")); - continue; - } - AddMethod(attributesTest, method, tests); - AddMethod(attributesBefore, method, before); - AddMethod(attributesAfter, method, after); - if (attributesBeforeClass.Length != 0) - { - if (method.IsStatic) - { - beforeClass.Add(method); - } - else - { - messagesForUser.Add(($"Метод {method.Name} содержит атрибут BeforeClass, но не является статическим", "")); - } - } - if (attributesAfterClass.Length != 0) - { - if (method.IsStatic) - { - afterClass.Add(method); - } - else - { - messagesForUser.Add(($"Метод {method.Name} содержит атрибут AfterClass, но не является статическим", "")); - } - } + messagesForUser.Add(($"Метод {method.Name} имеет два несовместимых атрибута", "")); + return; + } + AddMethod(attributesTest, method, tests); + AddMethod(attributesBefore, method, before); + AddMethod(attributesAfter, method, after); + if (attributesBeforeClass.Length != 0) + { + if (method.IsStatic) + { + beforeClass.Add(method); } - - if (tests.Count < 1) + else { - return messagesForUser; + messagesForUser.Add(($"Метод {method.Name} содержит атрибут BeforeClass, но не является статическим", "")); } - - messagesForUser.Add(($"Проверка тестов из {classDll.Name}", "")); - - RunMethodsWithAttributes(beforeClass.ToArray(), messagesForUser, null); - var tasks = new Task>[tests.Count]; - for (int i = 0; i < tests.Count; i++) - { - var test = tests[i]; - var user = messagesForUser; - tasks[i] = Task.Run(() => - { - var messagesFromCurrentTest = new List<(string, string)>(); - var attribute = (Test)Attribute.GetCustomAttribute(test, typeof(Test)); - if (attribute.Ignore != null) - { - return messagesFromCurrentTest; - } - object classInstance = Activator.CreateInstance(classDll); - RunMethodsWithAttributes(before.ToArray(), messagesFromCurrentTest, classInstance); - var message = ("", ""); - var watch = new Stopwatch(); - watch.Start(); - try - { - test.Invoke(classInstance, null); - } - catch (Exception exception) - { - watch.Stop(); - if (attribute.Expected == null) - { - message = ($"Тест {test.Name} не пройден: возникло исключение {exception.InnerException.GetType()}", $"Время: {watch.ElapsedMilliseconds} ms"); - } - else if (exception.InnerException.GetType() != attribute.Expected) - { - message = ($"Тест {test.Name} не пройден: ожидалось исключения типа {attribute.Expected}, возникло {exception.InnerException.GetType()}", $"Время: {watch.ElapsedMilliseconds} ms"); - } - else - { - message = ($"Тест {test.Name} пройден успешно", $"Время: {watch.ElapsedMilliseconds} ms"); - } - } - finally - { - watch.Stop(); - if (message.Item1 == "") - { - if (attribute.Expected == null) - { - message = ($"Тест {test.Name} пройден успешно", $"Время: {watch.ElapsedMilliseconds} ms"); - } - else - { - message = ($"Тест {test.Name} не пройден: ожидалось исключения типа {attribute.Expected}", $"Время: {watch.ElapsedMilliseconds} ms"); - } - } - } - user.Add(message); - RunMethodsWithAttributes(after.ToArray(), messagesFromCurrentTest, classInstance); - return messagesFromCurrentTest; - }); + } + if (attributesAfterClass.Length != 0) + { + if (method.IsStatic) + { + afterClass.Add(method); } - RunMethodsWithAttributes(afterClass.ToArray(), messagesForUser, null); - foreach (var task in tasks) + else { - messagesForUser = messagesForUser.Union(task.Result).ToList(); + messagesForUser.Add(($"Метод {method.Name} содержит атрибут AfterClass, но не является статическим", "")); } - return messagesForUser; } } } \ No newline at end of file diff --git a/MyNUnit/MyNUnit/MyNUnit.csproj b/MyNUnit/MyNUnit/MyNUnit.csproj index a184b89..5756fd0 100644 --- a/MyNUnit/MyNUnit/MyNUnit.csproj +++ b/MyNUnit/MyNUnit/MyNUnit.csproj @@ -2,8 +2,13 @@ Exe - net5.0 + net6.0 Windows + 10 + + + + diff --git a/MyNUnit/MyNUnit/Program.cs b/MyNUnit/MyNUnit/Program.cs index 074c43b..8001d21 100644 --- a/MyNUnit/MyNUnit/Program.cs +++ b/MyNUnit/MyNUnit/Program.cs @@ -1,12 +1,33 @@ -using System; +namespace MyNUnit; -namespace MyNUnit +using System; +using System.IO; + +class Program { - class Program + static void Main(string[] args) { - static void Main(string[] args) + if (args.Length == 0) + { + Console.WriteLine("Путь к папке не указан"); + return; + } + + if (Directory.Exists(args[0])) + { + Console.WriteLine("По данному пути ниичего не найдено."); + return; + } + + var myNUnit = new MyNUnit(); + var result = myNUnit.RunTests(args[0]); + foreach (var test in result) { - + Console.WriteLine(test.Item1); + if (test.Item2 != null) + { + Console.WriteLine(test.Item2); + } } } } \ No newline at end of file diff --git a/MyNUnit/MyNUnit/Test.cs b/MyNUnit/MyNUnit/Test.cs deleted file mode 100644 index f783a7d..0000000 --- a/MyNUnit/MyNUnit/Test.cs +++ /dev/null @@ -1,17 +0,0 @@ -using System; - -namespace MyNUnit -{ - public class Test : Attribute - { - public Type Expected { get; set; } - - public string Ignore { get; set; } - - public Test(Type expected, string ignore = null) - { - Expected = expected; - Ignore = ignore; - } - } -} \ No newline at end of file From 628057b11d1b1cd4624827075601b31a83442505 Mon Sep 17 00:00:00 2001 From: MikePuzanov Date: Mon, 28 Mar 2022 16:41:52 +0300 Subject: [PATCH 4/7] update appveyor.yml --- appveyor.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/appveyor.yml b/appveyor.yml index 9809100..d79f319 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,3 +1,6 @@ +image: Visual Studio 2022 + + build_script: - For /R %%I in (*.sln) do dotnet test %%I test: of \ No newline at end of file From abd13279a42f608973230dd590a8c94e5132c136 Mon Sep 17 00:00:00 2001 From: MikePuzanov Date: Mon, 28 Mar 2022 16:43:13 +0300 Subject: [PATCH 5/7] update appveyor.yml --- appveyor.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index d79f319..ec8ac0d 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,6 +1,5 @@ image: Visual Studio 2022 - build_script: - For /R %%I in (*.sln) do dotnet test %%I test: of \ No newline at end of file From 1f7823a4b76b33fbff26d2cf448254d08483899e Mon Sep 17 00:00:00 2001 From: MikePuzanov Date: Mon, 28 Mar 2022 17:05:41 +0300 Subject: [PATCH 6/7] change path to directory in tests --- MyNUnit/MyNUnit.Test/MyNUnit.Test.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MyNUnit/MyNUnit.Test/MyNUnit.Test.cs b/MyNUnit/MyNUnit.Test/MyNUnit.Test.cs index 4ea0bfb..c6253b8 100644 --- a/MyNUnit/MyNUnit.Test/MyNUnit.Test.cs +++ b/MyNUnit/MyNUnit.Test/MyNUnit.Test.cs @@ -23,7 +23,7 @@ public class Tests [NUnit.Framework.Test] public void TestForMessages() { - var result = myNUnit.RunTests("../../../../ForTests/bin/Debug/net5.0/"); + var result = myNUnit.RunTests("../../../../ForTests/bin/Debug/net6.0/"); foreach (var m in result) { Assert.IsTrue(answer.Contains(m.Item1)); From c3e04401f72c481319bd8706ad07afec8700fe80 Mon Sep 17 00:00:00 2001 From: MikePuzanov Date: Mon, 4 Apr 2022 02:48:20 +0300 Subject: [PATCH 7/7] fix bugs --- MyNUnit/AttributesMyNunit/After.cs | 6 +- MyNUnit/AttributesMyNunit/AfterClass.cs | 4 - MyNUnit/AttributesMyNunit/Before.cs | 4 - MyNUnit/AttributesMyNunit/BeforeClass.cs | 4 - MyNUnit/AttributesMyNunit/Test.cs | 4 +- MyNUnit/MyNUnit.Test/MyNUnit.Test.cs | 7 +- MyNUnit/MyNUnit/MyNUnit.cs | 152 +++++++++++++---------- 7 files changed, 92 insertions(+), 89 deletions(-) diff --git a/MyNUnit/AttributesMyNunit/After.cs b/MyNUnit/AttributesMyNunit/After.cs index 435747a..d837b06 100644 --- a/MyNUnit/AttributesMyNunit/After.cs +++ b/MyNUnit/AttributesMyNunit/After.cs @@ -3,13 +3,9 @@ using System; /// -/// Атрибут, которым обозначают методы, которые вызываются после каждого тестом +/// Атрибут, которым обозначают методы, которые вызываются после каждого теста /// [AttributeUsage(AttributeTargets.Method)] public class After : Attribute { - public After() - { - - } } \ No newline at end of file diff --git a/MyNUnit/AttributesMyNunit/AfterClass.cs b/MyNUnit/AttributesMyNunit/AfterClass.cs index 33da8ea..227ba29 100644 --- a/MyNUnit/AttributesMyNunit/AfterClass.cs +++ b/MyNUnit/AttributesMyNunit/AfterClass.cs @@ -8,8 +8,4 @@ [AttributeUsage(AttributeTargets.Method)] public class AfterClass : Attribute { - public AfterClass() - { - - } } \ No newline at end of file diff --git a/MyNUnit/AttributesMyNunit/Before.cs b/MyNUnit/AttributesMyNunit/Before.cs index 2194a2d..837c3a5 100644 --- a/MyNUnit/AttributesMyNunit/Before.cs +++ b/MyNUnit/AttributesMyNunit/Before.cs @@ -8,8 +8,4 @@ [AttributeUsage(AttributeTargets.Method)] public class Before : Attribute { - public Before() - { - - } } \ No newline at end of file diff --git a/MyNUnit/AttributesMyNunit/BeforeClass.cs b/MyNUnit/AttributesMyNunit/BeforeClass.cs index 4b7393c..67c202a 100644 --- a/MyNUnit/AttributesMyNunit/BeforeClass.cs +++ b/MyNUnit/AttributesMyNunit/BeforeClass.cs @@ -8,8 +8,4 @@ [AttributeUsage(AttributeTargets.Method)] public class BeforeClass : Attribute { - public BeforeClass() - { - - } } \ No newline at end of file diff --git a/MyNUnit/AttributesMyNunit/Test.cs b/MyNUnit/AttributesMyNunit/Test.cs index 48a9e9a..a009520 100644 --- a/MyNUnit/AttributesMyNunit/Test.cs +++ b/MyNUnit/AttributesMyNunit/Test.cs @@ -10,9 +10,9 @@ public class Test : Attribute { public Type Expected { get; set; } - public string Ignore { get; set; } + public string? Ignore { get; set; } - public Test(Type expected, string ignore = null) + public Test(Type expected, string? ignore = null) { Expected = expected; Ignore = ignore; diff --git a/MyNUnit/MyNUnit.Test/MyNUnit.Test.cs b/MyNUnit/MyNUnit.Test/MyNUnit.Test.cs index c6253b8..eb5015d 100644 --- a/MyNUnit/MyNUnit.Test/MyNUnit.Test.cs +++ b/MyNUnit/MyNUnit.Test/MyNUnit.Test.cs @@ -5,7 +5,7 @@ namespace MyNUnit.Test; public class Tests { - private readonly MyNUnit myNUnit = new MyNUnit(); + private readonly MyNUnit myNUnit = new (); private readonly string[] answer = new string[] { "Проверка тестов из Test1", @@ -13,10 +13,11 @@ public class Tests "Метод TestWithIncompatibleAttributes имеет два несовместимых атрибута", "В методе ExceptionInAfterClass возникло исключение: System.AggregateException", "Тест TestWithExpectedException пройден успешно", + "Тест TestShouldBeIgnored был игнорирован", "Тест TestWithoutExpected пройден успешно", "Тест TestBefore пройден успешно", - "Тест ExceptionExpectedButWasNull не пройден: ожидалось исключения типа System.ArgumentException", - "Тест OneExceptionExpectedButWasAnother не пройден: ожидалось исключения типа System.ArgumentException, возникло System.AggregateException", + "Тест ExceptionExpectedButWasNull не пройден: ожидалось исключение типа System.ArgumentException", + "Тест OneExceptionExpectedButWasAnother не пройден: ожидалось исключение типа System.ArgumentException, возникло System.AggregateException", "Тест NullExpectedButThrowException не пройден: возникло исключение System.ArgumentException" }; diff --git a/MyNUnit/MyNUnit/MyNUnit.cs b/MyNUnit/MyNUnit/MyNUnit.cs index 7b3da01..996e784 100644 --- a/MyNUnit/MyNUnit/MyNUnit.cs +++ b/MyNUnit/MyNUnit/MyNUnit.cs @@ -1,6 +1,7 @@ namespace MyNUnit; using System; +using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.IO; @@ -14,6 +15,8 @@ /// public class MyNUnit { + private ConcurrentBag<(string, string)> messages; + /// /// запуск тестов из .dll /// @@ -23,49 +26,45 @@ public class MyNUnit { var dlls = Directory.GetFiles(path, "*.dll"); var tasks = new Task>[dlls.Length]; - var message = new List<(string, string)>(); - Parallel.ForEach(dlls,dll => DoTestFromDll(dll, message)); - return message.ToArray(); + messages = new(); + Parallel.ForEach(dlls, dll => DoTestFromDll(dll)); + return messages.ToArray(); } - - private void DoTestFromDll(string dllPath, List<(string, string)> message) + + private void DoTestFromDll(string dllPath) { var dll = Assembly.LoadFrom(dllPath); var classes = dll.ExportedTypes.Where(t => t.IsClass); - Parallel.ForEach(classes, c => DoWorkInClass(c, message)); + Parallel.ForEach(classes, c => DoWorkInClass(c)); } - private void DoWorkInClass(Type classFromDll, List<(string, string)> messagesForUser) + private void DoWorkInClass(Type classFromDll) { - var after = new List(); - var before = new List(); - var beforeClass = new List(); - var afterClass = new List(); - var tests = new List(); + var testAttributes = new TestAttributes(); var methods = classFromDll.GetMethods(); - Parallel.ForEach(methods, method => GetAttributesAndDoBeforeAndAfterClass(method, after, before, beforeClass, afterClass, tests, messagesForUser)); - Parallel.ForEach(beforeClass, method => RunMethodsWithAttributes(method, messagesForUser, null)); - - if (tests.Count < 1) + Parallel.ForEach(methods, method => GetAttributesAndDoBeforeAndAfterClass(method, testAttributes)); + RunMethodsWithAttributes(testAttributes.BeforeClass, null); + + if (testAttributes.Tests.Count < 1) { return; } - messagesForUser.Add(($"Проверка тестов из {classFromDll.Name}", "")); + messages.Add(($"Проверка тестов из {classFromDll.Name}", "")); - Parallel.ForEach(tests, test => DoTest(test, messagesForUser, before, after, classFromDll)); - Parallel.ForEach(afterClass, method => RunMethodsWithAttributes(method, messagesForUser, null)); + Parallel.ForEach(testAttributes.Tests, test => DoTest(test, testAttributes, classFromDll)); + RunMethodsWithAttributes(testAttributes.AfterClass, null); } - private void DoTest(MethodInfo test, List<(string, string)> messagesFromCurrentTest, List before, - List after, Type classDll) + private void DoTest(MethodInfo test, TestAttributes testAttributes, Type classDll) { var attribute = (Test)Attribute.GetCustomAttribute(test, typeof(Test)); if (attribute.Ignore != null) { + messages.Add(($"Тест {test.Name} был игнорирован", "")); return; } - object classInstance = Activator.CreateInstance(classDll); - Parallel.ForEach(before, method => RunMethodsWithAttributes(method, messagesFromCurrentTest, classInstance)); + object classInstance = Activator.CreateInstance(classDll); + RunMethodsWithAttributes(testAttributes.Before, classInstance); var message = ("", ""); var watch = new Stopwatch(); watch.Start(); @@ -82,7 +81,7 @@ private void DoTest(MethodInfo test, List<(string, string)> messagesFromCurrentT } else if (exception.InnerException.GetType() != attribute.Expected) { - message = ($"Тест {test.Name} не пройден: ожидалось исключения типа {attribute.Expected}, возникло {exception.InnerException.GetType()}", $"Время: {watch.ElapsedMilliseconds} ms"); + message = ($"Тест {test.Name} не пройден: ожидалось исключение типа {attribute.Expected}, возникло {exception.InnerException.GetType()}", $"Время: {watch.ElapsedMilliseconds} ms"); } else { @@ -100,13 +99,13 @@ private void DoTest(MethodInfo test, List<(string, string)> messagesFromCurrentT } else { - message = ($"Тест {test.Name} не пройден: ожидалось исключения типа {attribute.Expected}", $"Время: {watch.ElapsedMilliseconds} ms"); + message = ($"Тест {test.Name} не пройден: ожидалось исключение типа {attribute.Expected}", $"Время: {watch.ElapsedMilliseconds} ms"); } } } - messagesFromCurrentTest.Add(message); - - Parallel.ForEach(after, method => RunMethodsWithAttributes(method, messagesFromCurrentTest, classInstance)); + messages.Add(message); + + RunMethodsWithAttributes(testAttributes.After, classInstance); } private void AddMethod(Attribute[] attributes, MethodInfo method, List list) @@ -117,72 +116,91 @@ private void AddMethod(Attribute[] attributes, MethodInfo method, List methods, object classIntstase) { - if (attribute.Length > 0) + foreach (MethodInfo method in methods) { - return 1; - } - - return 0; + try + { + method.Invoke(classIntstase, null); + } + catch (Exception e) + { + messages.Add(($"В методе {method.Name} возникло исключение: {e.InnerException.GetType()}", "")); + } + } } - - private void RunMethodsWithAttributes(MethodInfo method, List<(string, string)> messagesForUser, object ClassIntstase) + + private Attribute[][] GetCountAttributes(MethodInfo method) { - try + var types = new Type[] { typeof(Before), typeof(BeforeClass), typeof(Test), typeof(AfterClass), typeof(After)}; + var typesCount = new Attribute[5][]; + for (int i = 0; i < types.Length; i++) { - method.Invoke(ClassIntstase, null); - } - catch (Exception e) - { - messagesForUser.Add(($"В методе {method.Name} возникло исключение: {e.InnerException.GetType()}", "")); + typesCount[i] = Attribute.GetCustomAttributes(method).Where(t => t.GetType() == types[i]).ToArray(); } + return typesCount; } - private void GetAttributesAndDoBeforeAndAfterClass(MethodInfo method, List after, - List before, List beforeClass, List afterClass, List tests, - List<(string, string)> messagesForUser) + private int GetSumOfAttributesInMethod(Attribute[][] array) { - var attributesTest = Attribute.GetCustomAttributes(method).Where(t => t.GetType() == typeof(Test)).ToArray(); - var attributesBefore = Attribute.GetCustomAttributes(method).Where(t => t.GetType() == typeof(Before)).ToArray(); - var attributesAfter = Attribute.GetCustomAttributes(method).Where(t => t.GetType() == typeof(After)).ToArray(); - var attributesBeforeClass = Attribute.GetCustomAttributes(method).Where(t => t.GetType() == typeof(BeforeClass)).ToArray(); - var attributesAfterClass = Attribute.GetCustomAttributes(method).Where(t => t.GetType() == typeof(AfterClass)).ToArray(); var count = 0; - count += CheckAttributesInMethod(attributesTest); - count += CheckAttributesInMethod(attributesAfter); - count += CheckAttributesInMethod(attributesBefore); - count += CheckAttributesInMethod(attributesAfterClass); - count += CheckAttributesInMethod(attributesBeforeClass); - if (count > 1) + for (int i = 0;i < array.Length;i++) + { + count += array[i].Length; + } + return count; + } + + private void GetAttributesAndDoBeforeAndAfterClass(MethodInfo method, TestAttributes testAttributes) + { + var countOfAttributes = GetCountAttributes(method); + if (GetSumOfAttributesInMethod(countOfAttributes) > 1) { - messagesForUser.Add(($"Метод {method.Name} имеет два несовместимых атрибута", "")); + messages.Add(($"Метод {method.Name} имеет два несовместимых атрибута", "")); return; } - AddMethod(attributesTest, method, tests); - AddMethod(attributesBefore, method, before); - AddMethod(attributesAfter, method, after); - if (attributesBeforeClass.Length != 0) + AddMethod(countOfAttributes[0], method, testAttributes.Before); + AddMethod(countOfAttributes[2], method, testAttributes.Tests); + AddMethod(countOfAttributes[4], method, testAttributes.After); + if (countOfAttributes[1].Length != 0) { if (method.IsStatic) - { - beforeClass.Add(method); + { + testAttributes.BeforeClass.Add(method); } else { - messagesForUser.Add(($"Метод {method.Name} содержит атрибут BeforeClass, но не является статическим", "")); + messages.Add(($"Метод {method.Name} содержит атрибут BeforeClass, но не является статическим", "")); } } - if (attributesAfterClass.Length != 0) + if (countOfAttributes[3].Length != 0) { if (method.IsStatic) { - afterClass.Add(method); + testAttributes.AfterClass.Add(method); } else { - messagesForUser.Add(($"Метод {method.Name} содержит атрибут AfterClass, но не является статическим", "")); + messages.Add(($"Метод {method.Name} содержит атрибут AfterClass, но не является статическим", "")); } } } + private class TestAttributes + { + public TestAttributes() + { + After = new(); + Before = new(); + BeforeClass = new(); + AfterClass = new(); + Tests = new(); + } + + public List After { get; set; } + public List Before { get; set; } + public List BeforeClass { get; set; } + public List AfterClass { get; set; } + public List Tests { get; set; } + } } \ No newline at end of file