In the following example I am going to setup a class, a console app that calls that class, unit tests for nUnit, xUnit, and MSTest all in the same project, and a class method that determines if it is being called from one of the unit tests.
Start a new C# console app using .Net Core in Visual Studio 2019. Call it DetectUnitTest. Add a class called TargetClass that looks like this.
namespace DetectUnitTest
{
public static class TargetClass
{
public static int Add(int a, int b)
{
return a + b;
}
}
}
using System;
namespace DetectUnitTest
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(string.Format("{0} + {1} = {2}",
2,2,TargetClass.Add(2,2)));
}
}
}
Let's add the unit tests. Add a new class library project called UnitTests.
To Add MSTest, use NuGet to add these three packages
- Microsoft.Net.Test.Sdk
- MSTest.TestAdapter
- MSTest.TestFramework
To add nUnit, use NuGet to add these two packages
- NUnit
- NUnit3.TestAdapter
To Add xUnit, use NuGet to add these two packages
- xunit
- xunit.runner.visualstudio
Also add a reference to the DetectUnitTest project so we can test it.
Add classes to the UnitTests project called MSUnitTests, NUnitTests, and XUnitTests. We will add a simple test to each one.
MSUnitTests
using
DetectUnitTest;
using
Microsoft.VisualStudio.TestTools.UnitTesting;
namespace UnitTests
{
[TestClass]
public class MSUnitTests
{
[TestMethod]
public void
AddTest()
{
Assert.AreEqual(4,
TargetClass.Add(2, 2));
}
}
}
NUnitTests
using
DetectUnitTest;
using
NUnit.Framework;
namespace UnitTests
{
class NUnitTests
{
[Test]
public void
AddTest()
{
Assert.AreEqual(4,
TargetClass.Add(2, 2));
}
}
}
XUnitTests
using
DetectUnitTest;
using Xunit;
namespace UnitTests
{
public class XUnitTests
{
[Fact]
public void
AddTest()
{
Assert.Equal(4, TargetClass.Add(2, 2));
}
}
}
using
System.Collections.Generic;
using
System.Diagnostics;
using
System.Linq;
namespace DetectUnitTest
{
public static class DetectUnitTest
{
public static readonly List<string> UnitTestAttributes = new List<string>
{
"Xunit.FactAttribute",
"Xunit.TheoryAttribute",
"Nunit.TestAttribute",
"Nunit.TheoryAttribute",
"Microsoft.VisualStudio.TestTools.UnitTesting.TestMethodAttribute",
"Microsoft.VisualStudio.TestTools.UnitTesting.DataTestMethodAttribute"
};
private static bool? _IsRunningInUnitTest = null;
public static bool IsRunningInUnitTest
{
get
{
if (!_IsRunningInUnitTest.HasValue)
{
_IsRunningInUnitTest = false;
foreach (var f in new StackTrace().GetFrames())
{
if (f.GetMethod().GetCustomAttributes(false).Any(x =>
UnitTestAttributes.Contains(x.GetType().FullName)))
{
_IsRunningInUnitTest = true;
break;
}
}
}
return _IsRunningInUnitTest.Value;
}
}
}
}
using System;
namespace DetectUnitTest
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine(string.Format("{0} + {1} = {2}",
2,2,TargetClass.Add(2,2)));
Console.WriteLine(string.Format("Running in unit test = {0}", DetectUnitTest.IsRunningInUnitTest));
}
}
}
When we run the application now, the output looks like this.
Now let's see if it can detect when it's being called from the unit test classes. Add these tests to the Unit Tests.
MSUnitTests
[DataTestMethod]
[DataRow(true)]
public void
IsRunningUnitTest(bool
Expected)
{
Assert.AreEqual(Expected,
DetectUnitTest.DetectUnitTest.IsRunningInUnitTest);
}
NUnitTests
[Datapoint] bool IsTest = true;
[Theory]
public void
IsRunningUnitTest(bool
Expected)
{
Assert.AreEqual(Expected,
DetectUnitTest.DetectUnitTest.IsRunningInUnitTest);
}
xUnitTests
[Theory]
[InlineData(true)]
public void
IsRunningUnitTest(bool
Expected)
{
Assert.Equal(Expected,
DetectUnitTest.DetectUnitTest.IsRunningInUnitTest);
}
If you run the tests in TestExplorer now you will see all these tests are passing, so we were able to detect when we were running inside a test.
You can see the test explorer was able to homologate the results from multiple test frameworks. Take a moment to understand how impressive that is.
No comments:
Post a Comment