A common option in.NET 8 for creating and running unit tests in C# is the xUnit testing framework, which is essential to the software development process. In this thorough tutorial, we will go over key ideas and offer code samples as we examine the foundations of unit testing using xUnit.

Establishing a Model Project
The first step is to use xUnit to construct a small console application in C# and a unit test project for it.

# Create a new console application
dotnet new console -n PeterConsoleApp

# Create a new xUnit test project
dotnet new xunit -n PeterConsoleApp.Tests

Write Our Console Application
We just printed this article's title and my name, Peter, in the Program.cs file. as demonstrated by the code example below.

Console.WriteLine("Hi and Welcome to Peter Article on Unit Testing with xUnit in .NET 8: A Comprehensive Guide");

Create Our Calculator Class

We just create a simple Calculator class with simple functions such as Add, Subtract, Multiply, Divide, and the key one Dispose of as the code example below.
namespace PeterConsoleApp
{
    public class Calculator : IDisposable
    {
        // Add method
        public int Add(int a, int b)
        {
            return a + b;
        }

        // Subtract method
        public int Subtract(int a, int b)
        {
            return a - b;
        }

        // Multiply method
        public int Multiply(int a, int b)
        {
            return a * b;
        }

        // Divide method
        public double Divide(int a, int b)
        {
            if (b == 0)
            {
                throw new ArgumentException("Cannot divide by zero.");
            }

            return (double)a / b;
        }

        private bool disposed = false;

        protected virtual void Dispose(bool disposing)
        {
            if (!disposed)
            {
                if (disposing)
                {
                    // Dispose of managed resources here go here
                }

                // Dispose of unmanaged resources goes here , if any
                disposed = true;
            }
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        ~Calculator()
        {
            Dispose(false);
        }
    }
}


Data Source
We will create two files for our Data Source one is an interface and the other is a class as code example below.
namespace PeterConsoleApp
{
    public interface IDataSource
    {
        string GetData();
    }
}


namespace PeterConsoleApp
{
    public class DataService
    {
        private readonly IDataSource _dataSource;

        public DataService(IDataSource dataSource)
        {
            _dataSource = dataSource;
        }

        public string ProcessData()
        {
            return _dataSource.GetData().ToUpper();
        }
    }
}


Now we are all set to create our Unit Tests 😊

Writing Our First Test

Our preferred code editor should open the PeterConsoleApp.Tests project. XUnit automatically creates a test file named UnitTest1.cs. To replace UnitTest1.cs with the following code example, please refer to the below code example. As an example, we will create a simple test method named TestAddition. The [Fact] attribute indicates that this method is a test.
namespace PeterConsoleApp.Tests
{
    public class PeterConsoleAppTests
    {
        [Fact]
        public void TestAddition()
        {
           // Arrange
           int a = 2;
           int b = 3;

           // Act
           int result = a + b;

           // Assert
           Assert.Equal(5, result);
        }
    }
}


Arrange

Putting the required things and circumstances in place.

Act

Executing the operation or calling the tested procedure.

Assert
Confirming that the outcome meets expectations.

Running the Tests

Now, let's run our unit tests.
# Navigate to the test project directory
cd PeterConsoleApp.Tests

# Run the tests
dotnet test
# Navigate to the test project directory
cd PeterConsoleApp.Tests

# Run the tests
dotnet test


There should be an output indicating that one test has been run and passed.

Writing More Tests
Let's add a few more tests to cover different scenarios. Let's replace UnitTest1.cs with the following code example. We will add a subtraction test and a parameterized multiplication test using the [Theory] and [InlineData] attributes.
namespace PeterConsoleApp.Tests
{
    public class PeterConsoleAppTests
    {
        [Fact]
        public void TestSubtraction()
        {
            // Arrange
            int a = 5;
            int b = 3;

            // Act
            int result = a - b;

            // Assert
            Assert.Equal(2, result);
        }

        [Theory]
        [InlineData(2, 3, 6)]
        [InlineData(5, 4, 20)]
        [InlineData(0, 7, 0)]
        public void TestMultiplication(int a, int b, int expected)
        {
            // Act
            int result = a * b;

            // Assert
            Assert.Equal(expected, result);
        }
    }
}


Advanced Concepts

Test Fixture

Generally, a test fixture contains one or more test methods. It can be used to share setup and cleanup code between tests.
namespace PeterConsoleApp
{
    public class CalculatorFixture : IDisposable
    {
        public Calculator Calculator { get; private set; }

        public CalculatorFixture()
        {
            // Initialize resources, create instances, etc.
            Calculator = new Calculator();
        }

        public void Dispose()
        {
            // Clean up resources, dispose of instances, etc.
            Calculator.Dispose();
        }
    }
}


namespace PeterConsoleApp.Tests
{
    public class CalculatorTests : IClassFixture<CalculatorFixture>
    {
        private readonly CalculatorFixture _fixture;

        public CalculatorTests(CalculatorFixture fixture)
        {
            _fixture = fixture;
        }

        [Fact]
        public void TestAddition()
        {
            // Arrange
            Calculator calculator = _fixture.Calculator;
            int a = 5;
            int b = 10;

            // Act
            int result = calculator.Add(a, b);

            // Assert
            Assert.Equal(15, result);
        }
    }
}

Mocking
The use of mocking libraries, such as Moq, can help isolate code units for testing.
using Moq;

namespace PeterConsoleApp.Tests;
public class DataServiceTests
{
    [Fact]
    public void TestDataProcessing()
    {
        // Arrange
        var mockDataSource = new Mock<IDataSource>();
        mockDataSource.Setup(d => d.GetData()).Returns("HELLO, I AM Peter");

        var dataService = new DataService(mockDataSource.Object);

        // Act
        string result = dataService.ProcessData();

        // Assert
        Assert.Equal("HELLO, I AM Peter", result);
    }
}

HostForLIFE ASP.NET Core 8.0.1 Hosting

European best, cheap and reliable ASP.NET hosting with instant activation. HostForLIFE.eu is #1 Recommended Windows and ASP.NET hosting in European Continent. With 99.99% Uptime Guaranteed of Relibility, Stability and Performace. HostForLIFE.eu security team is constantly monitoring the entire network for unusual behaviour. We deliver hosting solution including Shared hosting, Cloud hosting, Reseller hosting, Dedicated Servers, and IT as Service for companies of all size.