{"id":1431,"date":"2025-03-11T22:00:00","date_gmt":"2025-03-11T21:00:00","guid":{"rendered":"https:\/\/demo.sidekick.be\/itenium\/testing-frameworks\/"},"modified":"2025-11-28T13:31:42","modified_gmt":"2025-11-28T12:31:42","slug":"testing-frameworks","status":"publish","type":"post","link":"https:\/\/demo.sidekick.be\/itenium\/blog\/dotnet\/testing-frameworks\/","title":{"rendered":".NET Testing Frameworks"},"content":{"rendered":"<p>Target audience: A developer switching frameworks \ud83d\ude42<\/p>\n<h1 id=\"test-suites\">Test Suites<\/h1>\n<p>Typically test classes and\/or methods are decorated with Attributes.<\/p>\n<table class=\"table-code\">\n<thead>\n<tr>\n<th><\/th>\n<th>NUnit<\/th>\n<th>xUnit<\/th>\n<th>MSTest<\/th>\n<th>TUnit<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Namespace<\/td>\n<td>NUnit.Framework<\/td>\n<td>Xunit<\/td>\n<td>Microsoft.VisualStudio<br \/>.TestTools.UnitTesting<\/td>\n<td>TUnit<\/td>\n<\/tr>\n<tr>\n<td>Class Attribute<\/td>\n<td><a href=\"https:\/\/docs.nunit.org\/articles\/nunit\/writing-tests\/attributes\/testfixture.html\">TestFixture<\/a> (optional)<\/td>\n<td><\/td>\n<td>TestClass<\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<td>Method Attribute<\/td>\n<td><a href=\"https:\/\/docs.nunit.org\/articles\/nunit\/writing-tests\/attributes\/test.html\">Test<\/a><\/td>\n<td>Fact<\/td>\n<td>TestMethod<\/td>\n<td>Test<\/td>\n<\/tr>\n<tr>\n<td>Ignoring<\/td>\n<td><a href=\"https:\/\/docs.nunit.org\/articles\/nunit\/writing-tests\/attributes\/ignore.html\">Ignore<\/a><\/td>\n<td>Fact(Skip=\u201d\u201d)<\/td>\n<td>Ignore<\/td>\n<td>Skip<\/td>\n<\/tr>\n<tr>\n<td><strong>Setup &amp; Teardown<\/strong><\/td>\n<td><\/td>\n<td><\/td>\n<td><\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<td>Before all tests<\/td>\n<td><a href=\"https:\/\/docs.nunit.org\/articles\/nunit\/writing-tests\/attributes\/onetimesetup.html\">OneTimeSetUp<\/a><\/td>\n<td>IClassFixture&lt;T&gt;<\/td>\n<td>ClassInitialize<\/td>\n<td>Before(Class)<\/td>\n<\/tr>\n<tr>\n<td>Before each test<\/td>\n<td><a href=\"https:\/\/docs.nunit.org\/articles\/nunit\/writing-tests\/attributes\/setup.html\">SetUp<\/a><\/td>\n<td>Constructor<\/td>\n<td>TestInitialize<\/td>\n<td>Before(Test)<\/td>\n<\/tr>\n<tr>\n<td>After each test<\/td>\n<td><a href=\"https:\/\/docs.nunit.org\/articles\/nunit\/writing-tests\/attributes\/teardown.html\">TearDown<\/a><\/td>\n<td>IDisposable.Dispose<\/td>\n<td>TestCleanup<\/td>\n<td>After(Test)<\/td>\n<\/tr>\n<tr>\n<td>After all tests<\/td>\n<td><a href=\"https:\/\/docs.nunit.org\/articles\/nunit\/writing-tests\/attributes\/onetimeteardown.html\">OneTimeTearDown<\/a><\/td>\n<td>IClassFixture&lt;T&gt;<\/td>\n<td>ClassCleanup<\/td>\n<td>After(Class)<\/td>\n<\/tr>\n<tr>\n<td><strong>Meta data<\/strong><\/td>\n<td><\/td>\n<td><\/td>\n<td><\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<td>Description<\/td>\n<td><a href=\"https:\/\/docs.nunit.org\/articles\/nunit\/writing-tests\/attributes\/description.html\">Description<\/a><\/td>\n<td><\/td>\n<td>Description<\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<td>Categories<\/td>\n<td><a href=\"https:\/\/docs.nunit.org\/articles\/nunit\/writing-tests\/attributes\/category.html\">Category<\/a><\/td>\n<td>Trait(\u201cCategory\u201d, \u201c\u201d)<\/td>\n<td>TestCategory<\/td>\n<td>Category<\/td>\n<\/tr>\n<tr>\n<td>Custom properties<\/td>\n<td><a href=\"https:\/\/docs.nunit.org\/articles\/nunit\/writing-tests\/attributes\/property.html\">Property<\/a><\/td>\n<td>Trait<\/td>\n<td>TestProperty<\/td>\n<td>Property<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h4 id=\"xunit-iclassfixture\">xUnit IClassFixture<\/h4>\n<p>Setup in xUnit doesn\u2019t work with Attributes!<br \/> xUnit injects the same <code>XUnitTestsFixture<\/code> to the constructor before running each <code>[Fact]<\/code>.<\/p>\n<p>It\u2019s also possible to do setup\/teardown for all tests within classes decorated with a <code>CollectionAttribute<\/code> with <code>ICollectionFixture&lt;T&gt;<\/code>, see <a href=\"https:\/\/xunit.net\/docs\/shared-context\">shared-context<\/a> for more info.<\/p>\n<pre><code class=\"language-c#\">public class XUnitTestsFixture : IDisposable\n{\n    public XUnitTestsFixture() { \/* BeforeAllTests *\/ }\n    public void Dispose() { \/* AfterAllTests *\/ }\n}\n\npublic class XUnitTestsWithSetUp : IClassFixture&lt;XUnitTestsFixture&gt;\n{\n    private readonly XUnitTestsFixture _fixture;\n\n    public XUnitTestsWithSetUp(XUnitTestsFixture fixture)\n    {\n        _fixture = fixture;\n    }\n\n    [Fact]\n    public void Test1() { }\n}\n<\/code><\/pre>\n<h2 id=\"assembly-setup\">Assembly setup<\/h2>\n<h3 id=\"xunit\">xUnit<\/h3>\n<p>As per the <code>IClassFixture&lt;T&gt;<\/code> example above, the <code>XUnitTestsFixture<\/code> will be injected in all test classes in the assembly.<\/p>\n<pre><code class=\"language-c#\">[assembly: AssemblyFixture(typeof(XUnitTestsFixture))]\n<\/code><\/pre>\n<h3 id=\"nunit\">NUnit<\/h3>\n<pre><code class=\"language-c#\">[SetUpFixture]\npublic class Config\n{\n    [OneTimeSetUp]\n    public void SetUp() { }\n\n    [OneTimeTearDown]\n    public void TearDown() { }\n}\n<\/code><\/pre>\n<h3 id=\"mstest\">MSTest<\/h3>\n<pre><code class=\"language-c#\">[TestClass]\npublic class MyTestClass\n{\n    [AssemblyInitialize]\n    public static void AssemblyInitialize(TestContext testContext)\n    {\n        \/\/ Or return Task!\n    }\n\n    [AssemblyCleanup]\n    public static void AssemblyCleanup()\n    {\n        \/\/ Or return Task!\n    }\n}\n<\/code><\/pre>\n<h3 id=\"tunit\">TUnit<\/h3>\n<pre><code class=\"language-c#\">public class TUnitSetup\n{\n  [Before(Assembly)]\n  public static async Task AssemblySetup() { }\n\n  [After(Assembly)]\n  public static async Task AssemblyTeardown()\n  {\n    \/\/ Runs after the last test in GetType().Assembly\n  }\n\n  [AfterEvery(Assembly)]\n  public static async Task AllAssembliesTeardown(AssemblyHookContext context)\n  {\n    \/\/ Runs after the last test in all assemblies\n    \/\/ For all Before\/After there exists a Before\/AfterEvery\n    \/\/ Aside from Test\/Class\/Assembly there also is TestSession\/TestDiscovery\n  }\n}\n<\/code><\/pre>\n<h1 id=\"assertions\">Assertions<\/h1>\n<pre><code class=\"language-c#\">bool? actual = true;\n\n\/\/ NUnit\nAssert.That(actual, Is.EqualTo(true));\n\n\/\/ xUnit\nAssert.Equal(true, actual);\n\n\/\/ MSTest\nAssert.AreEqual(true, actual);\n\n\/\/ TUnit\nawait Assert.That(actual).IsEqualTo(true);\n<\/code><\/pre>\n<h2 id=\"basic\">Basic<\/h2>\n<table class=\"table-code\">\n<thead>\n<tr>\n<th>NUnit<\/th>\n<th>xUnit<\/th>\n<th>MSTest<\/th>\n<th>TUnit<\/th>\n<th>Notes<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Is.EqualTo<\/td>\n<td>Equal<\/td>\n<td>AreEqual<\/td>\n<td>IsEqualTo<\/td>\n<td>Using IEquatable<T><\/T><\/td>\n<\/tr>\n<tr>\n<td>Is.Not.EqualTo<\/td>\n<td>NotEqual<\/td>\n<td>AreNotEqual<\/td>\n<td>IsNotEqualTo<\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<td>Is.Null<\/td>\n<td>Null<\/td>\n<td>IsNull<\/td>\n<td>IsNull<\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<td>Is.True<\/td>\n<td>True<\/td>\n<td>IsTrue<\/td>\n<td>IsTrue<\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<td>Is.SameAs<\/td>\n<td>Same<\/td>\n<td>AreSame<\/td>\n<td>IsSameReferenceAs<\/td>\n<td>Same referenced object<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2 id=\"strings\">Strings<\/h2>\n<p>All but NUnit use an overload to ignore case for Start\/End with.<\/p>\n<table class=\"table-code\">\n<thead>\n<tr>\n<th>NUnit<\/th>\n<th>xUnit<\/th>\n<th>MSTest<\/th>\n<th>TUnit<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Is.Empty<\/td>\n<td>Empty<\/td>\n<td><\/td>\n<td>IsEmpty<\/td>\n<\/tr>\n<tr>\n<td>Does.Contain<\/td>\n<td>Contains<\/td>\n<td>StringAssert.Contains<\/td>\n<td>Contains<\/td>\n<\/tr>\n<tr>\n<td>Does.Not.Contain<\/td>\n<td>DoesNotContain<\/td>\n<td>StringAssert.DoesNotMatch<\/td>\n<td>DoesNotContain<\/td>\n<\/tr>\n<tr>\n<td>Does.StartWith<\/td>\n<td>StartsWith<\/td>\n<td>StringAssert.StartsWith<\/td>\n<td>StartsWith<\/td>\n<\/tr>\n<tr>\n<td>Does.EndWith().IgnoreCase<\/td>\n<td>EndsWith<\/td>\n<td>StringAssert.EndsWith<\/td>\n<td>EndsWith<\/td>\n<\/tr>\n<tr>\n<td>Does.Match<\/td>\n<td>Matches<\/td>\n<td>StringAssert.Matches<\/td>\n<td>Matches<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h2 id=\"exceptions\">Exceptions<\/h2>\n<pre><code class=\"language-c#\">Action sut = () =&gt; throw new Exception(\"cause\");\nFunc&lt;Task&gt; asyncSut = () =&gt; throw new Exception(\"cause\");\n\n\/\/ NUnit\nvar ex = Assert.Throws&lt;Exception&gt;(() =&gt; sut(), \"failure message\");\nAssert.That(ex.Message, Is.EqualTo(\"cause\"));\n\nvar ex2 = Assert.ThrowsAsync&lt;Exception&gt;(() =&gt; asyncSut());\nAssert.That(ex2.Message, Is.EqualTo(\"cause\"));\n\n\n\/\/ xUnit\nvar ex = Assert.Throws&lt;Exception&gt;(sut);\nAssert.Equal(\"cause\", ex.Message);\n\nvar ex2 = await Assert.ThrowsAsync&lt;Exception&gt;(() =&gt; asyncSut());\nAssert.Equal(\"cause\", ex2.Message);\n\n\n\/\/ MSTest\n\/\/ DEPRECATED: ExpectedExceptionAttribute(typeof(Exception))\n\/\/ DEPRECATED: ThrowsException&lt;T&gt;()\nvar ex = Assert.ThrowsExactly&lt;Exception&gt;(sut);\nAssert.AreEqual(\"cause\", ex.Message);\n\nvar ex2 = await Assert.ThrowsExactlyAsync&lt;Exception&gt;(asyncSut);\nAssert.AreEqual(\"cause\", ex2.Message);\n\n\n\/\/ TUnit\n\/\/ Also: .WithMessageMatching and .WithInnerException\nawait Assert.That(sut).ThrowsExactly&lt;Exception&gt;().WithMessage(\"cause\");\n\nawait Assert.That(asyncSut)\n  .ThrowsExactly&lt;ArgumentException&gt;()\n  .WithMessageMatching(StringMatcher.AsRegex(\"^cause$\"));\n<\/code><\/pre>\n<h3 id=\"exact-vs-derived\">Exact vs Derived<\/h3>\n<p>The above assertions expect the exceptions to be of exactly the type provided. If you do not want a failure when the actual type is a derived type:<\/p>\n<ul>\n<li>xUnit: <code>Assert.ThrowsAny(Async)&lt;T&gt;<\/code><\/li>\n<li>NUnit: <code>Assert.Catch(Async)&lt;T&gt;<\/code><\/li>\n<li>MSTest: <code>Assert.Throws(Async)&lt;T&gt;<\/code><\/li>\n<li>TUnit: <code>var ex = Assert.Throws(Async)&lt;T&gt;(sut)<\/code><\/li>\n<\/ul>\n<h2 id=\"collections\">Collections<\/h2>\n<table class=\"table-code\">\n<thead>\n<tr>\n<th>NUnit<\/th>\n<th>xUnit<\/th>\n<th>MSTest<\/th>\n<th>TUnit<\/th>\n<th>Notes<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Is.Empty<\/td>\n<td>Empty<\/td>\n<td>Assert.IsEmpty<\/td>\n<td>IsEmpty<\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<td>Is.EqualTo<\/td>\n<td>Equal<\/td>\n<td>CollectionAssert.AreEqual<\/td>\n<td>IsEquivalent (overload)<\/td>\n<td>Same order<\/td>\n<\/tr>\n<tr>\n<td>Is.EquivalentTo<\/td>\n<td>Equivalent<\/td>\n<td>CollectionAssert.AreEquivalent<\/td>\n<td>IsEquivalent<\/td>\n<td>Allow different order<\/td>\n<\/tr>\n<tr>\n<td>Has.Some.EqualTo()<\/td>\n<td>Contains<\/td>\n<td>CollectionAssert.Contains<\/td>\n<td>Contains<\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<td>Contains.Item<\/td>\n<td>Contains<\/td>\n<td>CollectionAssert.Contains<\/td>\n<td><\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<td>Is.Ordered.Descending<\/td>\n<td><\/td>\n<td><\/td>\n<td>IsInOrder<br \/>IsInDescendingOrder<\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<td>Is.All.GreaterThan(1)<\/td>\n<td>All(col, x =&gt; Assert.True(x &gt; 1))<\/td>\n<td><\/td>\n<td>ContainsOnly<\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<td>Has.None.Null<\/td>\n<td>All<\/td>\n<td>CollectionAssert<br \/>.AllItemsAreNotNull<\/td>\n<td><\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<td>Has.Exactly(3).Items<\/td>\n<td><\/td>\n<td>Assert.HasCount<\/td>\n<td><\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<td>Is.SubsetOf<\/td>\n<td><\/td>\n<td>CollectionAssert.IsSubsetOf<\/td>\n<td><\/td>\n<td><\/td>\n<\/tr>\n<tr>\n<td>Is.Unique<\/td>\n<td><\/td>\n<td>CollectionAssert<br \/>.AllItemsAreUnique<\/td>\n<td>HasDistinctItems<\/td>\n<td><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h4 id=\"xunit-assertcollection\">xUnit Assert.Collection<\/h4>\n<p>Specific assertions per element in the collection.<\/p>\n<pre><code class=\"language-c#\">Assert.Collection(\n  collection,\n  el1 =&gt; Assert.Null(el1),\n  el2 =&gt; Assert.False(el2),\n  ...\n);\n<\/code><\/pre>\n<h4 id=\"nunit-dictionary-assertions\">NUnit Dictionary Assertions<\/h4>\n<pre><code class=\"language-c#\">var dict = new Dictionary&lt;int, int&gt;\n{\n  { 1, 4 },\n  { 2, 5 }\n};\n\nAssert.That(dict, Does.ContainKey(1).WithValue(4));\n\nAssert.That(dict, Contains.Value(4));\nAssert.That(dict, Does.ContainValue(5));\nAssert.That(dict, Does.Not.ContainValue(3));\n<\/code><\/pre>\n<h2 id=\"numbers\">Numbers<\/h2>\n<pre><code class=\"language-c#\">\/\/ xUnit\n\/\/ Only InRange\nAssert.InRange(actual, 0, 100);\n\n\/\/ NUnit\nAssert.That(actual, Is.InRange(0, 100));\nAssert.That(actual, Is.AtMost(0));\n\/\/ Also: AtLeast, Zero, LessThanOrEqualTo, Negative\/Positive\n\/\/ Greater\/LessThan uses IComparable\n\n\/\/ MSTest: N\/A\n\n\/\/ TUnit\nawait Assert.That(actual).IsBetween(0, 100);\nawait Assert.That(actual).IsLessThan(0);\n\/\/ Also: IsGreaterThan, IsNotLessThanOrEqualTo\n\/\/ Is(Not)Zero, IsNegative\/Positive\n<\/code><\/pre>\n<h2 id=\"soft-assertions\">Soft Assertions<\/h2>\n<p>A test stops running as soon as an assertion fails. But sometimes it is handy that all assertions still run so that you have more context to pinpoint the exact problem. Both xUnit and NUnit have a mechanism to do this.<\/p>\n<pre><code class=\"language-c#\">\/\/ xUnit\nAssert.Multiple(\n  () =&gt; Assert.NotEqual(12, 24),\n  () =&gt; Assert.NotNull(\"Hello world\")\n);\n\n\/\/ NUnit\nusing (Assert.EnterMultipleScope())\n{\n  Assert.That(12, Is.Not.EqualTo(24));\n  Assert.That(\"Hello world\", Is.Not.Null);\n}\n\n\/\/ TUnit\n\/\/ Both NUnit &amp; TUnit can also use block scoped using\nusing var _ = Assert.Multiple();\nawait Assert.That(12).IsNotEqualTo(24);\nawait Assert.That(\"Hello world\").IsNotNull();\n<\/code><\/pre>\n<p>Before NUnit 4.2 the syntax was: <a href=\"https:\/\/docs.nunit.org\/articles\/nunit\/writing-tests\/assertions\/multiple-asserts.html\"><code>Assert.Multiple(() =&gt; { \/* assertions *\/ })<\/code><\/a><\/p>\n<h2 id=\"nunit-and-tunit-only\">NUnit and TUnit Only<\/h2>\n<h4 id=\"dates\">Dates<\/h4>\n<pre><code class=\"language-c#\">\/\/ NUnit\nAssert.That(later, Is.EqualTo(now).Within(TimeSpan.FromHours(3.0)));\nAssert.That(later, Is.EqualTo(now).Within(3).Hours);\n\n\/\/ TUnit\nawait Assert.That(later).IsAfter(now);\nawait Assert.That(later).IsBetween(now, now.AddHours(3));\n<\/code><\/pre>\n<h4 id=\"directories\">Directories<\/h4>\n<p>Also: <code>Is.SamePath(OrUnder)<\/code><\/p>\n<pre><code class=\"language-c#\">\/\/ NUnit only\nAssert.That(\"\/folder1\/.\/junk\/..\/folder2\", Is.SubPathOf(\"\/folder1\/\"));\nAssert.That(new DirectoryInfo(\"c:\\temp\"), Does.Exist);\nAssert.That(new DirectoryInfo(\"c:\\temp\"), Is.Not.Empty);\n<\/code><\/pre>\n<h4 id=\"andor\">And\/Or<\/h4>\n<pre><code class=\"language-c#\">\/\/ NUnit\nAssert.That(3, Is.LessThan(5).Or.GreaterThan(10));\n\n\/\/ TUnit\nawait Assert.That(3).IsLessThan(5).Or.IsGreaterThan(10);\n<\/code><\/pre>\n<p><strong>TUnit<\/strong>: For more complicated AND\/OR logic, check <a href=\"https:\/\/thomhurst.github.io\/TUnit\/docs\/tutorial-assertions\/assertion-groups\">AssertionGroup.For<\/a><\/p>\n<h1>Extras<\/h1>\n<p><b>Stuff that came into being during the making of this post<\/b><\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/itenium-be\/DotNetUnitTestFrameworks\">Example UnitTests in NUnit, xUnit and MSTest<\/a><\/li>\n<\/ul>\n<p><b>Other interesting reads<\/b><\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/shouldly\/shouldly\" class=\"github\"><img decoding=\"async\" src=\"https:\/\/img.shields.io\/github\/stars\/shouldly\/shouldly.svg?style=social&#038;label=Star\" \/><\/a><a href=\"https:\/\/github.com\/shouldly\/shouldly\">shouldly\/shouldly<\/a>: Should testing for .NET\u2014the way assertions should be!<\/li>\n<\/ul>\n<h1>Updates<\/h1>\n<ul>\n<li> 12 March 2025: Updated to latest versions. Added TUnit, SoftAssertions, Throws derived, &#8230;<\/li>\n<\/ul>\n<h1> Package Versions <i class=\"fa fa-info-circle\" style=\"float: right; color: cornflowerblue; font-size: 28px\" title=\"Package versions used for this post and in the accompanying code on Github\"><\/i><\/h1>\n<p> NUnit: v4.3.2 <\/p>\n<p> xUnit: v2.9.3 <\/p>\n<p> MSTest.TestFramework: v3.8.2 <\/p>\n<p> TUnit: v0.18.9 <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Comparing .NET Testing Frameworks.<\/p>\n<p><a href=\"https:\/\/github.com\/xunit\/xunit\" class=\"github\"><img decoding=\"async\" src=\"https:\/\/img.shields.io\/github\/stars\/xunit\/xunit.svg?style=social&amp;label=Star\" \/><\/a><a href=\"https:\/\/github.com\/xunit\/xunit\">xunit\/xunit<\/a>: Community-focused unit testing tool <a href=\"https:\/\/github.com\/nunit\/nunit\" class=\"github\"><img decoding=\"async\" src=\"https:\/\/img.shields.io\/github\/stars\/nunit\/nunit.svg?style=social&amp;label=Star\" \/><\/a><a href=\"https:\/\/github.com\/nunit\/nunit\">nunit\/nunit<\/a>: NUnit Framework <a href=\"https:\/\/github.com\/microsoft\/testfx\" class=\"github\"><img decoding=\"async\" src=\"https:\/\/img.shields.io\/github\/stars\/microsoft\/testfx.svg?style=social&amp;label=Star\" \/><\/a><a href=\"https:\/\/github.com\/microsoft\/testfx\">microsoft\/testfx<\/a>: MSTest framework and adapter <a href=\"https:\/\/github.com\/thomhurst\/TUnit\" class=\"github\"><img decoding=\"async\" src=\"https:\/\/img.shields.io\/github\/stars\/thomhurst\/TUnit.svg?style=social&amp;label=Star\" \/><\/a><a href=\"https:\/\/github.com\/thomhurst\/TUnit\">thomhurst\/TUnit<\/a>: A modern, fast and flexible .NET testing framework<\/p>\n","protected":false},"author":1,"featured_media":2001,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[11],"tags":[13,21],"class_list":["post-1431","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet","tag-cheat-sheet","tag-testing"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v26.5 - https:\/\/yoast.com\/wordpress\/plugins\/seo\/ -->\n<title>.NET Testing Frameworks - Itenium<\/title>\n<meta name=\"robots\" content=\"noindex, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\".NET Testing Frameworks - Itenium\" \/>\n<meta property=\"og:description\" content=\"Comparing .NET Testing Frameworks.xunit\/xunit: Community-focused unit testing tool nunit\/nunit: NUnit Framework microsoft\/testfx: MSTest framework and adapter thomhurst\/TUnit: A modern, fast and flexible .NET testing framework\" \/>\n<meta property=\"og:url\" content=\"https:\/\/demo.sidekick.be\/itenium\/blog\/dotnet\/testing-frameworks\/\" \/>\n<meta property=\"og:site_name\" content=\"Itenium\" \/>\n<meta property=\"article:published_time\" content=\"2025-03-11T21:00:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2025-11-28T12:31:42+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/demo.sidekick.be\/itenium\/wp-content\/uploads\/2025\/11\/net-testing-frameworks.png\" \/>\n\t<meta property=\"og:image:width\" content=\"360\" \/>\n\t<meta property=\"og:image:height\" content=\"300\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"Usdevelop\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Usdevelop\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"5 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\/\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\/\/demo.sidekick.be\/itenium\/blog\/dotnet\/testing-frameworks\/\",\"url\":\"https:\/\/demo.sidekick.be\/itenium\/blog\/dotnet\/testing-frameworks\/\",\"name\":\".NET Testing Frameworks - Itenium\",\"isPartOf\":{\"@id\":\"https:\/\/demo.sidekick.be\/itenium\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\/\/demo.sidekick.be\/itenium\/blog\/dotnet\/testing-frameworks\/#primaryimage\"},\"image\":{\"@id\":\"https:\/\/demo.sidekick.be\/itenium\/blog\/dotnet\/testing-frameworks\/#primaryimage\"},\"thumbnailUrl\":\"https:\/\/demo.sidekick.be\/itenium\/wp-content\/uploads\/2025\/11\/net-testing-frameworks.png\",\"datePublished\":\"2025-03-11T21:00:00+00:00\",\"dateModified\":\"2025-11-28T12:31:42+00:00\",\"author\":{\"@id\":\"https:\/\/demo.sidekick.be\/itenium\/#\/schema\/person\/6ab401ce01e858184ee4a8667fe0f022\"},\"breadcrumb\":{\"@id\":\"https:\/\/demo.sidekick.be\/itenium\/blog\/dotnet\/testing-frameworks\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\/\/demo.sidekick.be\/itenium\/blog\/dotnet\/testing-frameworks\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/demo.sidekick.be\/itenium\/blog\/dotnet\/testing-frameworks\/#primaryimage\",\"url\":\"https:\/\/demo.sidekick.be\/itenium\/wp-content\/uploads\/2025\/11\/net-testing-frameworks.png\",\"contentUrl\":\"https:\/\/demo.sidekick.be\/itenium\/wp-content\/uploads\/2025\/11\/net-testing-frameworks.png\",\"width\":360,\"height\":300,\"caption\":\"three unit testing frameworks battling\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\/\/demo.sidekick.be\/itenium\/blog\/dotnet\/testing-frameworks\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\/\/demo.sidekick.be\/itenium\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\".NET Testing Frameworks\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\/\/demo.sidekick.be\/itenium\/#website\",\"url\":\"https:\/\/demo.sidekick.be\/itenium\/\",\"name\":\"Itenium\",\"description\":\"We build software. We build careers.\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\/\/demo.sidekick.be\/itenium\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\/\/demo.sidekick.be\/itenium\/#\/schema\/person\/6ab401ce01e858184ee4a8667fe0f022\",\"name\":\"Usdevelop\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\/\/demo.sidekick.be\/itenium\/#\/schema\/person\/image\/\",\"url\":\"https:\/\/secure.gravatar.com\/avatar\/cc8cf9b9e9d5bbe7e8d247907cc9ac8457bbfa2854b52eaddf6529adfe88ceab?s=96&d=mm&r=g\",\"contentUrl\":\"https:\/\/secure.gravatar.com\/avatar\/cc8cf9b9e9d5bbe7e8d247907cc9ac8457bbfa2854b52eaddf6529adfe88ceab?s=96&d=mm&r=g\",\"caption\":\"Usdevelop\"},\"sameAs\":[\"https:\/\/demo.sidekick.be\/itenium\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":".NET Testing Frameworks - Itenium","robots":{"index":"noindex","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"og_locale":"en_US","og_type":"article","og_title":".NET Testing Frameworks - Itenium","og_description":"Comparing .NET Testing Frameworks.xunit\/xunit: Community-focused unit testing tool nunit\/nunit: NUnit Framework microsoft\/testfx: MSTest framework and adapter thomhurst\/TUnit: A modern, fast and flexible .NET testing framework","og_url":"https:\/\/demo.sidekick.be\/itenium\/blog\/dotnet\/testing-frameworks\/","og_site_name":"Itenium","article_published_time":"2025-03-11T21:00:00+00:00","article_modified_time":"2025-11-28T12:31:42+00:00","og_image":[{"width":360,"height":300,"url":"https:\/\/demo.sidekick.be\/itenium\/wp-content\/uploads\/2025\/11\/net-testing-frameworks.png","type":"image\/png"}],"author":"Usdevelop","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Usdevelop","Est. reading time":"5 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/demo.sidekick.be\/itenium\/blog\/dotnet\/testing-frameworks\/","url":"https:\/\/demo.sidekick.be\/itenium\/blog\/dotnet\/testing-frameworks\/","name":".NET Testing Frameworks - Itenium","isPartOf":{"@id":"https:\/\/demo.sidekick.be\/itenium\/#website"},"primaryImageOfPage":{"@id":"https:\/\/demo.sidekick.be\/itenium\/blog\/dotnet\/testing-frameworks\/#primaryimage"},"image":{"@id":"https:\/\/demo.sidekick.be\/itenium\/blog\/dotnet\/testing-frameworks\/#primaryimage"},"thumbnailUrl":"https:\/\/demo.sidekick.be\/itenium\/wp-content\/uploads\/2025\/11\/net-testing-frameworks.png","datePublished":"2025-03-11T21:00:00+00:00","dateModified":"2025-11-28T12:31:42+00:00","author":{"@id":"https:\/\/demo.sidekick.be\/itenium\/#\/schema\/person\/6ab401ce01e858184ee4a8667fe0f022"},"breadcrumb":{"@id":"https:\/\/demo.sidekick.be\/itenium\/blog\/dotnet\/testing-frameworks\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/demo.sidekick.be\/itenium\/blog\/dotnet\/testing-frameworks\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/demo.sidekick.be\/itenium\/blog\/dotnet\/testing-frameworks\/#primaryimage","url":"https:\/\/demo.sidekick.be\/itenium\/wp-content\/uploads\/2025\/11\/net-testing-frameworks.png","contentUrl":"https:\/\/demo.sidekick.be\/itenium\/wp-content\/uploads\/2025\/11\/net-testing-frameworks.png","width":360,"height":300,"caption":"three unit testing frameworks battling"},{"@type":"BreadcrumbList","@id":"https:\/\/demo.sidekick.be\/itenium\/blog\/dotnet\/testing-frameworks\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/demo.sidekick.be\/itenium\/"},{"@type":"ListItem","position":2,"name":".NET Testing Frameworks"}]},{"@type":"WebSite","@id":"https:\/\/demo.sidekick.be\/itenium\/#website","url":"https:\/\/demo.sidekick.be\/itenium\/","name":"Itenium","description":"We build software. We build careers.","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/demo.sidekick.be\/itenium\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/demo.sidekick.be\/itenium\/#\/schema\/person\/6ab401ce01e858184ee4a8667fe0f022","name":"Usdevelop","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/demo.sidekick.be\/itenium\/#\/schema\/person\/image\/","url":"https:\/\/secure.gravatar.com\/avatar\/cc8cf9b9e9d5bbe7e8d247907cc9ac8457bbfa2854b52eaddf6529adfe88ceab?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/cc8cf9b9e9d5bbe7e8d247907cc9ac8457bbfa2854b52eaddf6529adfe88ceab?s=96&d=mm&r=g","caption":"Usdevelop"},"sameAs":["https:\/\/demo.sidekick.be\/itenium"]}]}},"_links":{"self":[{"href":"https:\/\/demo.sidekick.be\/itenium\/wp-json\/wp\/v2\/posts\/1431","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/demo.sidekick.be\/itenium\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/demo.sidekick.be\/itenium\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/demo.sidekick.be\/itenium\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/demo.sidekick.be\/itenium\/wp-json\/wp\/v2\/comments?post=1431"}],"version-history":[{"count":3,"href":"https:\/\/demo.sidekick.be\/itenium\/wp-json\/wp\/v2\/posts\/1431\/revisions"}],"predecessor-version":[{"id":2266,"href":"https:\/\/demo.sidekick.be\/itenium\/wp-json\/wp\/v2\/posts\/1431\/revisions\/2266"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/demo.sidekick.be\/itenium\/wp-json\/wp\/v2\/media\/2001"}],"wp:attachment":[{"href":"https:\/\/demo.sidekick.be\/itenium\/wp-json\/wp\/v2\/media?parent=1431"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/demo.sidekick.be\/itenium\/wp-json\/wp\/v2\/categories?post=1431"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/demo.sidekick.be\/itenium\/wp-json\/wp\/v2\/tags?post=1431"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}