Unit testing has been around since the beginning of software testing. Unit testing lays the groundwork for the rest of your software delivery and testing pipelines, making it one of the most crucial phases of the software development lifecycle.
Unit testing entails writing code that examines other blocks of code to ensure that they work as intended. Unit tests examine the most fundamental unit of any application. Only after you have mastered unit testing can you move on to other types of testing – like performance testing, visual testing, and integration testing.
Unit testing typically necessitates the use of unique unit testing frameworks for each programming language and framework. The three most popular unit testing frameworks in ASP.NET Core, for example, are NUnit, xUnit, and MSTest. These frameworks differ significantly in terms of features and implementation.
Most developers want to know which frameworks work best in which situations and how to choose the best one for their specific C# code. This article compares and contrasts the NUnit, xUnit, and MSTest frameworks.
Adapted from JUnit, NUnit is a free unit testing framework for all .NET languages. NUnit was released under the MIT license and is entirely open source. Although the first iteration of NUnit was a port of JUnit, version 3 has been entirely rewritten from the ground up with several new features and support for a number of .NET platforms.
NUnit works by isolating the entire application into distinct modules. Each module is independently tested to ensure that the goal is met. The static methods of NUnit's custom attributes and the Assert class’s rich set of assertions make it easy to create unit test cases. Custom attributes of NUnit test runners indicate the presence of unit testing code in these classes or functions. Assert classes, on the other hand, are used to determine whether or not the block of code under review meets a predetermined condition. If an assertion fails (i.e., the condition is not met), the assertion method call does not return, and an error is generated to indicate that the test failed. Custom attributes include TestFixture, SetUp, TearDown, Test, Category, Ignore, TestCase, Repeat, MaxTime, and so on.
xUnit.net is a community-focused, free, and open source unit testing tool for the .NET frameworks. It was written by the creators of the NUnit framework, James Newkirk and Brad Wilson, and it’s licensed under the Apache 2 OSI. When it comes to unit testing, xUnit works well with Xamarin, ReSharper, CodeRush, TestDriven.NET, and Console Runner. The “x” in xUnit refers to the programming language for which the framework was created – for example, we have JUnit (for Java code), NUnit (for C#, VB.NET, and other .NET languages), CppUnit (for C++), and PyUnit (for Python).
xUnit is designed in such a way that it allows you to control your tests by adding new attributes. It adds custom functionality to the Assert class by extending the Contains, DoesNotContain, Equal, NotEqual, InRange, and NotInRange methods. It also supports two types of unit tests that use [Fact] or [Theory] annotations to test assertions. The xUnit.net test runner uses the [Fact] attribute to identify a “normal” unit test that is always true (a test method that takes no method arguments and tests invariant conditions). Meanwhile, [Theory] annotation tests accept multiple inputs and are true for a specific set of data. By default, xUnit runs all tests in separate class files in parallel. This allows us to run our tests in parallel without any special configuration.
MSTest is a unit testing framework that was developed by Microsoft and integrated into their Visual Studio IDE. There is also an open source version called MSTest V2, which is now available for download from NuGet.org. This allows you to assess the code by using a wide range of attributes at the method and class levels instead of using external tools.
The main features of MSTest V2 are:
It’s open source – The MSTest V2 project is open source and hosted on GitHub. Its open repositories are Microsoft/testfx and Microsoft/testfx-docs.
It provides cross-platform support – MSTest V2 allows developers to create tests for the .NET Framework, .NET Core, and ASP.NET Core on Linux, Mac, and Windows.
It enables data-driven testing – By enabling data-driven testing, MSTest V2 allows users to specify the behavior of their tests. This way, a single method can be executed multiple times by passing different input arguments.
It supports parallel test execution – MSTest V2 supports parallel test execution, which speeds up the whole process. In-assembly parallel test execution makes it possible to run tests concurrently via RunSettings or annotations.
It enables customization through annotations – The MSTest V2 framework allows you to customize the test execution lifecycle through annotations like [TestClass], [TestMethod], [TestInitialize], and [TestCleanup].
It’s extensible – Its features can now be extended with unique test attributes and unique assertions, just like other test frameworks.
The three most popular .NET unit testing frameworks (discussed above) each function differently by providing testing teams with various features. In this section, we will compare each feature separately.
Criteria | NUnit Test | xUnit Test | MSTest V2 |
Grouping Tests by Class | [TestFixture] | Not Available | [TestClass] |
Test Setup and Teardown (Note: The setup method takes a constructor, while a teardown needs an IDisposable interface.) | [SetUp] [TearDown] | Not Available | [TestInitialize] [TestCleanup] |
Single Test Case Declaration | [Test] | [Fact] / [Theory] | [TestMethod] |
Multiple Data Test Cases Declaration | [TestCase] | [Theory] [InlineData] | [DataTestMethod] [DataRow] |
Repeat Initialization for Each Test | [SetUp] [TearDown] | [Ctor], [IDisposable] | [TestInitialize] [TestCleanup] |
One-Time Initialization for All Tests in One Class | [OneTimeSetUp] [OneTimeTearDown] | [MemberData] Or [ClassData] [MethodMember] or [PropertyMember] | [ClassInitialize] [ClassCleanup] |
One-Time Initialization for All Tests in One Assembly | Dedicated class with [SetUpFixture] + [OneTimeSetUp] [OneTimeTearDown] | [MemberData] Or [ClassData],[PropertyMember] | [TestClass] + [AssemblyInitialize] [AssemblyCleanup] |
Execution in Isolation | Configurable | Default support | Default support |
Skipping a Test | [Fact (Skip=” reason”)] | [Ignore(“reason”)] | [Ignore] |
Documentation | Comprehensive and well-maintained documentation. Available . | Does not have well-maintained documentation. Available . | Comprehensive and well-maintained documentation. Available . |
Below is a sample test case that starts a browser locally, executes a very simple test using NUnit and Chrome web drivers, and then closes out the browser instance.
1using NUnit.Framework;2using OpenQA.Selenium;3using OpenQA.Selenium.Chrome;4using OpenQA.Selenium.Support.UI;5namespace WebDriver_CSharp_Example6{7[TestFixture]8public class Chrome_Sample_test9{10private IWebDriver driver;11public string homeURL;12[Test(Description="Check SauceLabs Homepage for Login Link")]13publicvoidLogin_is_on_home_page() {14homeURL = "https://www.SauceLabs.com";15driver.Navigate().GoToUrl(homeURL);16WebDriverWait wait = new WebDriverWait(driver,17System.TimeSpan.FromSeconds(15));18wait.Until(driver =>19driver.FindElement(By.XPath("//a[@href='/beta/login']")));20IWebElement element =21driver.FindElement(By.XPath("//a[@href='/beta/login']"));22Assert.AreEqual("Sign In", element.GetAttribute("text"));23}24[TearDown]25publicvoidTearDownTest()26{27driver.Close();28}29[SetUp]30publicvoidSetupTest()31{32homeURL = "http://SauceLabs.com";33driver = new ChromeDriver();34}35}36}3738
The following is a sample unit test written using the xUnit framework in C# to validate arithmetic methods of addition and multiplication:
1public class MathUnitxTest2{3[Fact]4public void Task_TestAddition()5{6var numA=12, numB=4, result=16;7var calculatedSum = MathOperation.Add(numA, numB);8Assert.Equal(expectedValue, calculatedSum, 1);9}10[Fact]11public void Task_TestMultiplication()12{13var numA=5, numB=4, result=20;14var calculatedOutput= MathOperation.Multiply(num1, num2);15Assert.Equal(result, calculatedOutput, 2);16}17}
The following is a sample unit test written using the MSTest framework in C# to validate arithmetic methods of addition and subtraction:
1namespace Messages.Tests;2using Microsoft.VisualStudio.TestTools.UnitTesting;34[TestClass]5public class ArithmeticMsTest6{7[DataTestMethod]8[DataRow(1, 2, 3)]9[DataRow(2, 2, 4)]10[DataRow(-1, 4, 3)]11public void Task_TestAddition(int x, int y, int expected)12{13int sum = Basic.add(x, y);14Assert.AreEqual(sum, expected);15}16[DataTestMethod]17[DataRow(1, 2, -1)]18[DataRow(2, 2, 0)]19[DataRow(3, 2, 1)]20public void Task_TestSubtraction(int x, int y, int expected)21{22int res = Basic.sub(x, y);23Assert.AreEqual(res, expected);24}25}
The Xunit, Nunit, and MSTest .NET frameworks have all evolved over the last few years. For instance, compared to MSTest V1, MSTest V2 offers significantly improved usability and compatibility with other tools. With their developers offering more community-focused support, the xUnit and NUnit frameworks have also grown more sophisticated.
Ultimately, all three frameworks provide features and tools that enable elaborate unit testing. Based on the above comparison of their distinguishing features, you can see that it comes down to personal preference. If we had to choose a favorite, we would pick NUnit due to its straightforward naming conventions for attributes and assertions. It can also be used along with Selenium and web drivers to run a variety of automated unit tests – including cross-browser testing.