From 84f4bc5fcde7c88209b23cb0bfc06b5e9fd0e8e7 Mon Sep 17 00:00:00 2001 From: SeMuell Date: Thu, 16 Oct 2025 18:32:45 +0200 Subject: [PATCH] Add MSTestV4 Support and add Proper Test Projects Signed-off-by: SeMuell --- ArchUnit.sln | 18 +++++ .../ArchUnitNET.MSTestV2.csproj | 3 +- .../ArchUnitNET.MSTestV2Tests.csproj | 4 +- .../RuleEvaluationTests.cs | 12 +-- .../ArchUnitNET.MSTestV3Tests.csproj | 22 +++++ .../RuleEvaluationTests.cs | 81 +++++++++++++++++++ ArchUnitNET.MSTestV4/ArchRuleAssert.cs | 23 ++++++ ArchUnitNET.MSTestV4/ArchRuleExtensions.cs | 28 +++++++ .../ArchUnitNET.MSTestV4.csproj | 29 +++++++ .../ArchUnitNET.MSTestV4Tests.csproj | 22 +++++ ArchUnitNET.MSTestV4Tests/MSTestSettings.cs | 1 + .../RuleEvaluationTests.cs | 81 +++++++++++++++++++ 12 files changed, 314 insertions(+), 10 deletions(-) create mode 100644 ArchUnitNET.MSTestV3Tests/ArchUnitNET.MSTestV3Tests.csproj create mode 100644 ArchUnitNET.MSTestV3Tests/RuleEvaluationTests.cs create mode 100644 ArchUnitNET.MSTestV4/ArchRuleAssert.cs create mode 100644 ArchUnitNET.MSTestV4/ArchRuleExtensions.cs create mode 100644 ArchUnitNET.MSTestV4/ArchUnitNET.MSTestV4.csproj create mode 100644 ArchUnitNET.MSTestV4Tests/ArchUnitNET.MSTestV4Tests.csproj create mode 100644 ArchUnitNET.MSTestV4Tests/MSTestSettings.cs create mode 100644 ArchUnitNET.MSTestV4Tests/RuleEvaluationTests.cs diff --git a/ArchUnit.sln b/ArchUnit.sln index abcde8c4..b511f6d0 100644 --- a/ArchUnit.sln +++ b/ArchUnit.sln @@ -48,6 +48,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "InterfaceAssembly", "TestAs EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FilteredDirectoryUnavailableTypesAssembly", "TestAssemblies\FilteredDirectoryUnavailableTypesAssembly\FilteredDirectoryUnavailableTypesAssembly.csproj", "{AA695589-8CCC-4474-9A7F-01A6376C375A}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ArchUnitNET.MSTestV3Tests", "ArchUnitNET.MSTestV3Tests\ArchUnitNET.MSTestV3Tests.csproj", "{F9856A37-C0E0-453C-888F-D794856D3404}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ArchUnitNET.MSTestV4Tests", "ArchUnitNET.MSTestV4Tests\ArchUnitNET.MSTestV4Tests.csproj", "{9858F5A1-356B-4CF0-8E50-62F2E881CC36}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ArchUnitNET.MSTestV4", "ArchUnitNET.MSTestV4\ArchUnitNET.MSTestV4.csproj", "{50F0F64A-F4A2-47E5-82E9-B66F07CE4198}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -142,6 +148,18 @@ Global {AA695589-8CCC-4474-9A7F-01A6376C375A}.Debug|Any CPU.Build.0 = Debug|Any CPU {AA695589-8CCC-4474-9A7F-01A6376C375A}.Release|Any CPU.ActiveCfg = Release|Any CPU {AA695589-8CCC-4474-9A7F-01A6376C375A}.Release|Any CPU.Build.0 = Release|Any CPU + {F9856A37-C0E0-453C-888F-D794856D3404}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {F9856A37-C0E0-453C-888F-D794856D3404}.Debug|Any CPU.Build.0 = Debug|Any CPU + {F9856A37-C0E0-453C-888F-D794856D3404}.Release|Any CPU.ActiveCfg = Release|Any CPU + {F9856A37-C0E0-453C-888F-D794856D3404}.Release|Any CPU.Build.0 = Release|Any CPU + {9858F5A1-356B-4CF0-8E50-62F2E881CC36}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9858F5A1-356B-4CF0-8E50-62F2E881CC36}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9858F5A1-356B-4CF0-8E50-62F2E881CC36}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9858F5A1-356B-4CF0-8E50-62F2E881CC36}.Release|Any CPU.Build.0 = Release|Any CPU + {50F0F64A-F4A2-47E5-82E9-B66F07CE4198}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {50F0F64A-F4A2-47E5-82E9-B66F07CE4198}.Debug|Any CPU.Build.0 = Debug|Any CPU + {50F0F64A-F4A2-47E5-82E9-B66F07CE4198}.Release|Any CPU.ActiveCfg = Release|Any CPU + {50F0F64A-F4A2-47E5-82E9-B66F07CE4198}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/ArchUnitNET.MSTestV2/ArchUnitNET.MSTestV2.csproj b/ArchUnitNET.MSTestV2/ArchUnitNET.MSTestV2.csproj index b9a5d45c..60f3d22d 100644 --- a/ArchUnitNET.MSTestV2/ArchUnitNET.MSTestV2.csproj +++ b/ArchUnitNET.MSTestV2/ArchUnitNET.MSTestV2.csproj @@ -3,7 +3,7 @@ netstandard2.0;net462 true ArchUnit C# MSTestV2 Extension - MSTestV2 Extension for the C# Version of ArchUnit (see: archunit.org) + MSTestV2 Extension (compatible with MSTestV3) for the C# Version of ArchUnit (see: archunit.org) Apache-2.0 https://github.com/TNG/ArchUnitNET test;arch;archunit;mstest;mstestv2 @@ -17,7 +17,6 @@ true - diff --git a/ArchUnitNET.MSTestV2Tests/ArchUnitNET.MSTestV2Tests.csproj b/ArchUnitNET.MSTestV2Tests/ArchUnitNET.MSTestV2Tests.csproj index 661c89f7..57fc6d39 100644 --- a/ArchUnitNET.MSTestV2Tests/ArchUnitNET.MSTestV2Tests.csproj +++ b/ArchUnitNET.MSTestV2Tests/ArchUnitNET.MSTestV2Tests.csproj @@ -7,8 +7,8 @@ - - + + diff --git a/ArchUnitNET.MSTestV2Tests/RuleEvaluationTests.cs b/ArchUnitNET.MSTestV2Tests/RuleEvaluationTests.cs index 621fa150..903301c5 100644 --- a/ArchUnitNET.MSTestV2Tests/RuleEvaluationTests.cs +++ b/ArchUnitNET.MSTestV2Tests/RuleEvaluationTests.cs @@ -31,14 +31,14 @@ public static void Setup(TestContext context) public void ArchRuleAssertTest() { ArchRuleAssert.FulfilsRule(_architecture, _trueRule); - Assert.ThrowsExactly(() => + Assert.ThrowsException(() => ArchRuleAssert.FulfilsRule(_architecture, _falseRule) ); Assert.AreEqual( _expectedErrorMessage, RemoveAssertionText( Assert - .ThrowsExactly(() => + .ThrowsException(() => ArchRuleAssert.FulfilsRule(_architecture, _falseRule) ) .Message @@ -51,13 +51,13 @@ public void ArchRuleExtensionsTest() { _architecture.CheckRule(_trueRule); _trueRule.Check(_architecture); - Assert.ThrowsExactly(() => _architecture.CheckRule(_falseRule)); - Assert.ThrowsExactly(() => _falseRule.Check(_architecture)); + Assert.ThrowsException(() => _architecture.CheckRule(_falseRule)); + Assert.ThrowsException(() => _falseRule.Check(_architecture)); Assert.AreEqual( _expectedErrorMessage, RemoveAssertionText( Assert - .ThrowsExactly(() => + .ThrowsException(() => _architecture.CheckRule(_falseRule) ) .Message @@ -67,7 +67,7 @@ public void ArchRuleExtensionsTest() _expectedErrorMessage, RemoveAssertionText( Assert - .ThrowsExactly(() => _falseRule.Check(_architecture)) + .ThrowsException(() => _falseRule.Check(_architecture)) .Message ) ); diff --git a/ArchUnitNET.MSTestV3Tests/ArchUnitNET.MSTestV3Tests.csproj b/ArchUnitNET.MSTestV3Tests/ArchUnitNET.MSTestV3Tests.csproj new file mode 100644 index 00000000..d5463a71 --- /dev/null +++ b/ArchUnitNET.MSTestV3Tests/ArchUnitNET.MSTestV3Tests.csproj @@ -0,0 +1,22 @@ + + + + net9.0 + false + TNG Technology Consulting GmbH + true + + + + + + + + + + + + + + + diff --git a/ArchUnitNET.MSTestV3Tests/RuleEvaluationTests.cs b/ArchUnitNET.MSTestV3Tests/RuleEvaluationTests.cs new file mode 100644 index 00000000..881a516c --- /dev/null +++ b/ArchUnitNET.MSTestV3Tests/RuleEvaluationTests.cs @@ -0,0 +1,81 @@ +using ArchUnitNET.Domain; +using ArchUnitNET.Fluent; +using ArchUnitNET.Fluent.Extensions; +using ArchUnitNET.Loader; +using ArchUnitNET.MSTestV2; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using static ArchUnitNET.Fluent.ArchRuleDefinition; + +namespace ArchUnitNET.MSTestV3Tests +{ + [TestClass] + public class RuleEvaluationTests + { + private static Architecture _architecture; + private static string _expectedErrorMessage; + private static IArchRule _falseRule; + private static IArchRule _trueRule; + + [ClassInitialize] + public static void Setup(TestContext context) + { + _architecture = new ArchLoader() + .LoadAssemblies(System.Reflection.Assembly.Load("ArchUnitNET.MSTestV3Tests")) + .Build(); + _trueRule = Classes().That().Are(typeof(RuleEvaluationTests)).Should().Exist(); + _falseRule = Classes().That().Are(typeof(RuleEvaluationTests)).Should().NotExist(); + _expectedErrorMessage = _falseRule.Evaluate(_architecture).ToErrorMessage(); + } + + [TestMethod] + public void ArchRuleAssertTest() + { + ArchRuleAssert.FulfilsRule(_architecture, _trueRule); + Assert.ThrowsExactly(() => + ArchRuleAssert.FulfilsRule(_architecture, _falseRule) + ); + Assert.AreEqual( + _expectedErrorMessage, + RemoveAssertionText( + Assert + .ThrowsExactly(() => + ArchRuleAssert.FulfilsRule(_architecture, _falseRule) + ) + .Message + ) + ); + } + + [TestMethod] + public void ArchRuleExtensionsTest() + { + _architecture.CheckRule(_trueRule); + _trueRule.Check(_architecture); + Assert.ThrowsExactly(() => _architecture.CheckRule(_falseRule)); + Assert.ThrowsExactly(() => _falseRule.Check(_architecture)); + Assert.AreEqual( + _expectedErrorMessage, + RemoveAssertionText( + Assert + .ThrowsExactly(() => + _architecture.CheckRule(_falseRule) + ) + .Message + ) + ); + Assert.AreEqual( + _expectedErrorMessage, + RemoveAssertionText( + Assert + .ThrowsExactly(() => _falseRule.Check(_architecture)) + .Message + ) + ); + } + + private static string RemoveAssertionText(string exceptionMessage) + { + return exceptionMessage.Replace("Assert.Fail failed. ", string.Empty); + } + } +} diff --git a/ArchUnitNET.MSTestV4/ArchRuleAssert.cs b/ArchUnitNET.MSTestV4/ArchRuleAssert.cs new file mode 100644 index 00000000..585207f6 --- /dev/null +++ b/ArchUnitNET.MSTestV4/ArchRuleAssert.cs @@ -0,0 +1,23 @@ +using ArchUnitNET.Domain; +using ArchUnitNET.Fluent; +using ArchUnitNET.Fluent.Extensions; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace ArchUnitNET.MSTestV4 +{ + public static class ArchRuleAssert + { + /// + /// Verifies that the architecture meets the criteria of the archrule. + /// + /// The architecture to be tested + /// The rule to test the architecture with + public static void FulfilsRule(Architecture architecture, IArchRule archRule) + { + if (!archRule.HasNoViolations(architecture)) + { + Assert.Fail(archRule.Evaluate(architecture).ToErrorMessage()); + } + } + } +} diff --git a/ArchUnitNET.MSTestV4/ArchRuleExtensions.cs b/ArchUnitNET.MSTestV4/ArchRuleExtensions.cs new file mode 100644 index 00000000..f0c3d4e5 --- /dev/null +++ b/ArchUnitNET.MSTestV4/ArchRuleExtensions.cs @@ -0,0 +1,28 @@ +using ArchUnitNET.Domain; +using ArchUnitNET.Fluent; + +namespace ArchUnitNET.MSTestV4 +{ + public static class ArchRuleExtensions + { + /// + /// Verifies that the architecture meets the criteria of the archrule. + /// + /// The rule to test the architecture with + /// The architecture to be tested + public static void Check(this IArchRule archRule, Architecture architecture) + { + ArchRuleAssert.FulfilsRule(architecture, archRule); + } + + /// + /// Verifies that the architecture meets the criteria of the archrule. + /// + /// The architecture to be tested + /// The rule to test the architecture with + public static void CheckRule(this Architecture architecture, IArchRule archRule) + { + ArchRuleAssert.FulfilsRule(architecture, archRule); + } + } +} diff --git a/ArchUnitNET.MSTestV4/ArchUnitNET.MSTestV4.csproj b/ArchUnitNET.MSTestV4/ArchUnitNET.MSTestV4.csproj new file mode 100644 index 00000000..862709ba --- /dev/null +++ b/ArchUnitNET.MSTestV4/ArchUnitNET.MSTestV4.csproj @@ -0,0 +1,29 @@ + + + netstandard2.0;net462 + true + ArchUnit C# MSTestV4 Extension + MSTestV4 Extension for the C# Version of ArchUnit (see: archunit.org) + Apache-2.0 + https://github.com/TNG/ArchUnitNET + test;arch;archunit;mstest;mstestv2 + False + TNG Technology Consulting GmbH + TngTech.ArchUnitNET.MSTestV4 + false + true + snupkg + README.md + true + + + + + + + + + + + + diff --git a/ArchUnitNET.MSTestV4Tests/ArchUnitNET.MSTestV4Tests.csproj b/ArchUnitNET.MSTestV4Tests/ArchUnitNET.MSTestV4Tests.csproj new file mode 100644 index 00000000..f763d165 --- /dev/null +++ b/ArchUnitNET.MSTestV4Tests/ArchUnitNET.MSTestV4Tests.csproj @@ -0,0 +1,22 @@ + + + + net9.0 + false + TNG Technology Consulting GmbH + true + + + + + + + + + + + + + + + diff --git a/ArchUnitNET.MSTestV4Tests/MSTestSettings.cs b/ArchUnitNET.MSTestV4Tests/MSTestSettings.cs new file mode 100644 index 00000000..8baf5232 --- /dev/null +++ b/ArchUnitNET.MSTestV4Tests/MSTestSettings.cs @@ -0,0 +1 @@ +[assembly: DoNotParallelize] diff --git a/ArchUnitNET.MSTestV4Tests/RuleEvaluationTests.cs b/ArchUnitNET.MSTestV4Tests/RuleEvaluationTests.cs new file mode 100644 index 00000000..950f3a8c --- /dev/null +++ b/ArchUnitNET.MSTestV4Tests/RuleEvaluationTests.cs @@ -0,0 +1,81 @@ +using ArchUnitNET.Domain; +using ArchUnitNET.Fluent; +using ArchUnitNET.Fluent.Extensions; +using ArchUnitNET.Loader; +using ArchUnitNET.MSTestV4; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using static ArchUnitNET.Fluent.ArchRuleDefinition; + +namespace ArchUnitNET.MSTestV4Tests +{ + [TestClass] + public class RuleEvaluationTests + { + private static Architecture _architecture; + private static string _expectedErrorMessage; + private static IArchRule _falseRule; + private static IArchRule _trueRule; + + [ClassInitialize] + public static void Setup(TestContext context) + { + _architecture = new ArchLoader() + .LoadAssemblies(System.Reflection.Assembly.Load("ArchUnitNET.MSTestV4Tests")) + .Build(); + _trueRule = Classes().That().Are(typeof(RuleEvaluationTests)).Should().Exist(); + _falseRule = Classes().That().Are(typeof(RuleEvaluationTests)).Should().NotExist(); + _expectedErrorMessage = _falseRule.Evaluate(_architecture).ToErrorMessage(); + } + + [TestMethod] + public void ArchRuleAssertTest() + { + ArchRuleAssert.FulfilsRule(_architecture, _trueRule); + Assert.ThrowsExactly(() => + ArchRuleAssert.FulfilsRule(_architecture, _falseRule) + ); + Assert.AreEqual( + _expectedErrorMessage, + RemoveAssertionText( + Assert + .ThrowsExactly(() => + ArchRuleAssert.FulfilsRule(_architecture, _falseRule) + ) + .Message + ) + ); + } + + [TestMethod] + public void ArchRuleExtensionsTest() + { + _architecture.CheckRule(_trueRule); + _trueRule.Check(_architecture); + Assert.ThrowsExactly(() => _architecture.CheckRule(_falseRule)); + Assert.ThrowsExactly(() => _falseRule.Check(_architecture)); + Assert.AreEqual( + _expectedErrorMessage, + RemoveAssertionText( + Assert + .ThrowsExactly(() => + _architecture.CheckRule(_falseRule) + ) + .Message + ) + ); + Assert.AreEqual( + _expectedErrorMessage, + RemoveAssertionText( + Assert + .ThrowsExactly(() => _falseRule.Check(_architecture)) + .Message + ) + ); + } + + private static string RemoveAssertionText(string exceptionMessage) + { + return exceptionMessage.Replace("Assert.Fail failed. ", string.Empty); + } + } +}