Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / DevOps / unit-testing

Unit Testing with NUnit: Guidelines for Existing Codebases

0.00/5 (No votes)
12 Jun 2024CPOL1 min read 2.9K   14  
This article provides actionable insights into leveraging NUnit for unit testing in established codebases, enhancing code quality and reliability.

Introduction

In the realm of software development, unit tests are indispensable for code quality and stability. While Test-Driven Development (TDD) is ideal, integrating unit tests into pre-existing codebases can be tricky. This article aims to provide guidelines for writing unit tests using NUnit, for existing codebases.

The Scenario

Consider an Inventory Management System consisting of a Class Library DataAccessLayer and a C# Project InventoryManagementSystem.

The Class Library DataAccessLayer contains a DatabaseTransactionsclass, which inherits from DbContext , and the DataAccessLayer contains an Entity class ProductEntity and a Repository class ProductRepository

DatabaseTransactions

C#
public class DatabaseTransactions : DbContext
{
   public DatabaseTransactions() : base("name=conStr"){}	
   public virtual DbSet<ProductEntity> Product { get; set; }	
   
   protected override void OnModelCreating(DbModelBuilder modelBuilder)
   {
	 modelBuilder.Entity<ProductEntity>().ToTable("tblProduct");
   }
}

ProductEntity

C#
public class ProductEntity
{
   public int ID { get; set; }
   public string ProductName { get; set; }
   public int UnitPrice { get; set; }
   public int Quantity { get; set; }
}

ProductRepository

C#
public class ProductRepository
{
    private readonly DatabaseTransactions transaction;
	
    public ProductRepository(DatabaseTransactions _transaction) 
    { 
       transaction = _transaction; 
    }
    public int AddProduct(ProductEntity _productEntity)
    {
       try
       {
           transaction.Product.Add(_productEntity);
           return transaction.SaveChanges();      
       }
       catch (Exception ex)
       {
           return -1;
       }
    }
}

Setting up InventoryManagementSystem.Test Project

Add Unit Test Project InventoryManagementSystem.Test and Incorporate NuGet Packages for NUnit and Moq in the InventoryManagementSystem.Test Project to Facilitate DatabaseTransactionClass Mocking.

Add DataAccessLayer Solution Reference for Mocking DatabaseTransaction and testing ProductRepository methods within InventoryManagementSystem.Test Project.

Writing Unit Tests with NUnit

Identify Testable Units

Before diving into writing tests, it's essential to identify the units of code that can be tested in isolation. In our scenario, the ProductRepository class's AddProduct method is a suitable candidate for testing.

Establishing a Foundation

Add a class ProductRepositoryTest, and mention [TestFixture] which is used to mark a class as containing test fixtures. we adhere to the Arrange, Act and Assert (AAA) principle for unit testing.

C#
[TestFixture]
public class ProductRepositoryTest
{
   [Test]
   public void AddProduct_OnSuccessful_ShouldReturnOne()
   {
      //Arrange - Initializing Product Entity that will be passed to AddProduct method
      var _ProductEntity = new ProductEntity()
      {
         ProductName = "Computer Table",
         UnitPrice = 25000,
         Quantity = 500,
      };  
     
      //productData will act as Dataset which will be utilized in mocking DatabaseTransections
      var productData = new List<ProductEntity>().AsQueryable(); 
      
      //we create a mock object of the <code>DbSet<ProductEntity></code> class using Moq. This mock object will simulate the behavior of a DbSet for testing purposes.  
      var mockSet = new Mock<DbSet<ProductEntity>>();
      mockSet.As<IQueryable<ProductEntity>>().Setup(m => m.GetEnumerator()).Returns(productData.GetEnumerator());
      mockSet.As<IQueryable<ProductEntity>>().Setup(m => m.Expression).Returns(productData.Expression);
      mockSet.As<IQueryable<ProductEntity>>().Setup(m => m.ElementType).Returns(productData.ElementType);
      mockSet.As<IQueryable<ProductEntity>>().Setup(m => m.Provider).Returns(productData.Provider);
      
      //Now we create a mock object of the <code>DatabaseTransactions </code>class using Moq. This mock object will simulate the behavior of a database context for testing purposes.  
      var mockContext = new Mock<DatabaseTransactions>();
      mockContext.Setup(c => c.Product).Returns(mockSet.Object);
     
      //initializing ProductRepository with mockedObject of DataBaseTransections class
      var repository = new ProductRepository(mockContext.Object);
        
      //Act
      int result = repository.AddProduct(_ProductEntity);
       
      //Assert
      Assert.That(result, Is.EqualTo(1));
    }
}

Conclusion

As showcased in this article, using NUnit and Moq, we can write concise and targeted unit tests for existing code without extensive modifications. By following these guidelines, developers can enhance the maintainability and reliability of their software systems while minimizing disruption to the existing codebase.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)