xUnit.NET is a free, open-source platform available to perform unit testing for our .NET applications. It supports multiple languages like c#, VB.NET & other .NET languages. This article will explore how to create a test project using xUnit.NET and perform the unit tests on methods developed in some other projects. Before starting with some practical examples, let's understand how many types of tests there are in xUnit.NET. There are two types of tests, as listed below:
- Facts: These are the tests that are always true. Also, these tests don't accept parameters, meaning whatever data we need to test against our logic must be hard-coded inside the examination.
- Theory: These are the conditional tests true for a specific data set. These are parameterized tests that can accept outside parameters. It can accept the parameters in various ways, which we will discuss later in this document.
Let's create a new project to understand how we can perform unit testing using xUnit.NET.
First, open Visual Studio and create a new project.
Step 1: Select "C#" as a programming language in the first drop-down. If C# were selected as a default programming language at the time of Visual Studio installation, it would be selected by default.
Step 2: Select the project type "Test" in the third drop-down to filter the list of project types below. By default, you will find Web selected in the drop-down.
Step 3: Select "xUnit Test Project" from the filtered project type list and click "Next."
Step 4: Name your project, check the checkbox to place the solution in the same directory, and click "Next."
Step 5: Select the target framework and click "Create" to create your project. The target framework is in .NET 6.0, as I am using Visual Studio 2022.
Step 6: Let's create another project under the same solution in which we will write a few methods on which we will perform our unit tests.
Step 7: Let's create a class in the web application and write a few methods to multiply and concatenate strings.
Step 8: Now add this project reference to the test project so we can write a few tests for the methods mentioned above.
Once the project reference is added to the test project, you will see that the project has been added to the dependencies of the test project. Now we can use the methods created in the class in our tests by referencing the project namespace. If you look at the test project, you will find that a class named "UnitTest1.cs" is already designed. This is the class where we will write our unit tests.
Step 9: Let's play with some code and check how it works. Here comes a catch; first, we will start with Fact and understand how to test our methods using Fact. Below is the code written in "UnitTest1.cs" to test the methods for passing conditions.
- Test 1 (MultiplyPass): Here, we defined three variables two are input, and the third one is the expected output. We called the multiply method from our web project to calculate the result, and then comes the central part; we are using the "Assert" class, which belongs to the xUnit namespace. This class has various methods to perform testing, like comparing the numeric and string data, finding some data, and a few bool-type ways that only resemble and return the response. Here we used the "Equal" method of the "Assert" class to compare whether the output produced by the process matches the expected result or not.
- Test 2 (FindPass): There are also three variables: two are input, and the third is to search. Here we used the concrete method from our web project, which will return the concatenated string, and using the "Contains" method of "Assert," we will test whether the expected text exists in the supplied series or not.
Here we can see that both our tests are passed. Now let's write a few tests that will fail in the run.
- This is the simplest way to pass parameters to any Theory. Using InlineData, we pass the parameters as an array to the Theory. The critical point to note here is that the length and the type of the array must match the parameters defined for the Theory. Let's create a Theory and pass the test data using the InlineData attribute.
In the above example, we passed two sets of data to a single Theory to test, out of which one passed and the other one failed. Note that each set of InlineData creates a separate execution of MultiplyTheory.
Also, as mentioned, in case of an incorrect number of parameters and/or wrong data type, the debugger itself will show the error indicating that the InlineData does not match the method parameters as shown below.
If we do not want to pass constants as the testing parameters to the method, the alternative way is to use ClassData. This attribute takes the type that xUnit will use to get the data. To implement ClassData, we will need to create a class that must implement IEnumerable<object> interface. This call will return a list which will be an array of objects which xUnit will use as method parameters to perform the test. Below is the code snippet for using ClassData as a parameter for the Theory.
The ClassData attribute is easy to pass parameters to the Theories. However, if we don't want to create an additional class for passing the test parameters, we can use the MemberData attribute. MemberData uses static property or method to fetch data for the Theory. The MemberData attribute can only fetch data from IEnumerable<object> property in the test class. Let's create a static property in the UnitTest1.cs class, which will return the list of objects to be passed to the Theory.