Codechef4u is a community for computer professionals,by computer professionals,just like you; who loves sharing and helping each others,Join them
Share your post

Writing Unit tests in C# with moq

Writing Unit testing in C# with moq

What is Unit testing?

Wikipedia definition
Unit testing is a software testing method by which individual units of source code, sets of one or more computer program modules together with associated control data, usage procedures, and operating procedures, are tested to determine whether they are fit for use.

Reference: https://en.wikipedia.org/wiki/Unit_testing

What is Moq?

Moq is the mocking library for .NET developed that take full advantage of .NET 3.5 (i.e. Linq expression trees) and C# 3.0 features (i.e. lambda expressions) that make it the most productive, type-safe and refactoring-friendly mocking library available. And it supports mocking interfaces as well as classes.

Installing Moq:

You can download Moq from GitHub and add the appropriate references to your project, or you can install it using nugget package manager.



Unit testing in VS 2013 with Moq:

I want to test validation business logic for my finance web application following business entities I am using for product data.

  public class Product
   {
      public int ProductId { get; set; }
 
      public string ProductName { get; set; }
 
      public decimal Price { get; set; }
 
      public ProductCategory Category { get; set; }
 
      public string ImageUrl { get; set; }
   }

Product data validation logic and used interfaces for notication:

namespace C4RandDWebApp
{
    public class ProductDataValidation
    {
        private readonly ILogger _logger;
        private readonly IEmailer _emailer;
 
        public ProductDataValidation(ILogger Logger, IEmailer Emailer)
        {
            _logger = Logger;
            _emailer = Emailer;
        }
 
 
        public bool ValidateProductame(Product Product)
        {
            if (string.IsNullOrEmpty(Product.ProductName))
                return false;
           {
                     _logger.LogWarning("Invalid username" + Product.ProductName);
                    // Email internet dev
                    _emailer.SendWarningEmail(Product.ProductName,
                        "Invalid username");
          }
            return true;
        }

        public bool ValidateProductPrice(Product Product)
        {
            if (Product.Price == null || Product.Price == 0M)
                return false;
            return true;
        }

        public bool ValidateProductCategory(Product Product)
        {
            if (string.IsNullOrEmpty(Product.Category.CategoryName))
                return false;
            return true;
        }
    }
}
 


Created unit testing project named C4Testing and added  all required dll reference to project. 

Created following test class inside project that unit tests all scenarios for my application product data validation. 

Unit testing Class with Moq:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Moq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using C4RandDWebApp;
 
namespace C4Testing
{
    /// <summary>
    ///This is a test class for Product validation and is intended
    ///to contain all Product validation Unit Tests
    ///</summary>
    [TestClass]
    class ProductDataValidationTests
    {
        // Mocks
        private Mock<ILogger> _mockLogger;
        private Mock<IEmailer> _mockEmailer;
 
       //Declaration
        private IProductDataValidation _ProductValidation;
 
 
        //initalize
        [TestInitialize]
        public void ProductValiatotInitialise()
        {
            _mockLogger = new Mock<ILogger>();
            _mockEmailer = new Mock<IEmailer>();
            _ProductValidation = new C4RandDWebApp.ProductDataValidation(_mockLogger.Object, _mockEmailer.Object);
 
        }
 
 
        #region Sad Path
 
        /// <summary>
        /// Validates Product name. 
        /// Result is invalid Product Name.
        /// </summary>
        [TestMethod]
        public void ChaekEmptyProductName()
        {
            var target = _ProductValidation;
            var product = new Product()
            {
                ProductName = "",
                Price = 115,
                Category = new ProductCategory()
              {
                  CategoryName = "Book"
              },
                ImageUrl = @"C:/data"
 
            };
            Assert.IsFalse(target.ValidateProductame(product));
 
        }
 
        #endregion
 
 
        #region Happy Path
        /// <summary>
        /// validates Product name. 
        /// Result is valid Product Name.
        /// </summary>
        [TestMethod]
        public void ChaekValidProductName()
        {
            var target = _ProductValidation;
            var product = new Product()
            {
                ProductName = "CodeChef4u SQL rcipies",
                Price = 500,
                Category = new ProductCategory()
                {
                    CategoryName = "Book"
                },
                ImageUrl = @"C:/data"
 
            };
            Assert.IsTrue(target.ValidateProductame(product));
 
        }
        #endregion
    }
 

Creating Unit Tests with C#

Creating Unit Tests using C# and Visual Studio

Creating C4ShopDataValidation Library project for product data validation

Steps:

1. Open Visual Studio.

2. On the File menu=> New=>click Project.

3. New Project dialog box appears.

4. Installed Templates=> click Visual C#.

5. In the list of application types, click Class Library.

6. In Name box, type “C4ShopDataValidation” and then click OK.

Example:

Sample methods under test

   public bool ValidateProductame(ProductProduct)
        {
            if (string.IsNullOrEmpty(Product.ProductName))
                returnfalse;
 
            returntrue;
        }
 

 

public bool ValidatePrductNameWithSpecialChar(Product Product,out string ErrorMessage)
        {
            var regexItem = new Regex("^[a-zA-Z0-9 ]*$");
            if (regexItem.IsMatch(Product.ProductName))
            {
                ErrorMessage = "Special characters not allowed";
                return false;
            }
            ErrorMessage = "";
            return true;
        }

 

Create C4Test Project for unit testing:

Steps:

1.  File menu=>Add=> New Project .

2.  New Project dialog box=> expand Installed=>expand Visual C#=>Test.

3.  Appears list of templates=>select Unit Test Project.

4.  In the Name box, enter BankTest, and then choose OK.

5.  Provide nem “C4Test” now project is added to the the C4Shop solution.

6.  In the C4Test project, add required references i.e  C4ShopDataValidation,BusnessEntities.

7.  Rename existing Class Class.1 or Add new if you want

8.  Start writing test cases.

Example:

 Unit test methods for product name validation   


   [TestClass]
    public class ProductDataValidationTests
    {
 
       //Declaration
        private IProductDataValidation _ProductValidation;
 
 
        //initalize
        [TestInitialize]
        public void ProductDataValidationInitialise()
        {
       
            _ProductValidation = new ProductDataValidation();
 
        }
 
 
        #region Sad Path
 
       
        [TestMethod]
        public void ChaekEmptyProductName()
        {
            var target = _ProductValidation;
            var product = new Product()
            {
                ProductName = "",
                Price = 115,
                Category = new ProductCategory()
              {
                  CategoryName = "Book"
              },
                ImageUrl = @"C:/data"
 
            };
            Assert.IsFalse(target.ValidateProductame(product));
 
        }
 
        [TestMethod]
        public void ChaekBadProductNameForSpecialChar()
        {
            string ExpectedErroMessage = "Special characters not allowed";
            string TargetMessage;
            var target = _ProductValidation;
            var product = new Product()
            {
                ProductName = "CodeChef4u ) SQL rcipies",
                Price = 500,
                Category = new ProductCategory()
                {
                    CategoryName = "Book"
                },
                ImageUrl = @"C:/data"
 
            };
            var isFailed=target.ValidatePrductNameWithSpecialChar(product,out TargetMessage);
            Assert.AreEqual(ExpectedErroMessage, TargetMessage);
        }
    }

 

 

Return output parameter from Stored Procedure

Return output parameter from Stored Procedure in C#

In this Beginner level article I will explain how to use and return value from Stored Procedure using Output Parameter in C#.

In following example stored procedure checks for existing record If found it will return one parameter continue with value 1 and stop inserting any new product.

Example:

Your stored procedure:

-- =============================================
-- Author:                     Nagnath Kendre
-- Create date: <Create Date,,>
-- Description: Add uniqe product data
-- =============================================
CREATE PROCEDURE InsertProducts_SP
            -- Add the parameters for the stored procedure here
       @ProductName [nvarchar](100),
             @UnitPrice float,
       @CategoryID int,
       @Continue int OUTPUT
AS
BEGIN
 
    DECLARE @ChkRecordExist INT
            SELECT @ChkRecordExist=COUNT(ID) FROM Products
            WHERE ProductName=@ProductName and CategoryID=@CategoryID
            IF @ChkRecordExist=0
            BEGIN
           
    SELECT @Continue = 0
 
     --insert query here
     INSERT INTO Products
           (
            [ProductName] ,
            [Description],
            [UnitPrice],
            [CategoryID])
VALUES
( @ProductName,'',@UnitPrice,@CategoryID)
 
  END
 
  ELSE
  BEGIN
            SELECT @Continue = 1
  END
END
GO

 

C# Code:

        /// <summary>
        /// inserts a new Products.
        /// </summary>
        public bool CreateProducts (Product product)
        {
            //protection code
            if (product == null) return false;
            var dbcommand = _sQlClientFactory.CreateCommand();
            // Create
            dbcommand.CommandType = CommandType.StoredProcedure;
            dbcommand.CommandText = "InsertProducts_SP";
 
            dbcommand.Parameters.Add(new SqlParameter("@ProductName",  product.Name));
 
            dbcommand.Parameters.Add(new SqlParameter("@Price", product.Price));
 
            dbcommand.Parameters.Add(new SqlParameter("@CategoryId", product.Category));
           
 
            //adding output parameter as preventive reason
            //if found record no need to add proceed for update
            SqlParameter outParamter = new SqlParameter();
            outParamter.ParameterName = "@Continue";
            outParamter.Direction = System.Data.ParameterDirection.Output;
            outParamter.DbType = System.Data.DbType.Int32;
            dbcommand.Parameters.Add(outParamter);
 
            var isInserted=ExecuteTransaction(dbcommand);
 
            var countinueUpdate = Convert.ToInt32(outParamter.Value);
            if (countinueUpdate == 1)
            { ContinueUpdate = true;
            }
            return isInserted;
            }

 

public bool ExecuteTransaction(IDbCommand Command)
        {
            var status = false;
                using (var myCon= SqlClient.CreateConnection(connString))
                {
                    myCon.Open();
 
                    using (Command)
                    {
                        Command.Connection = myCon;
                      
                        var rowsAffected = Command.ExecuteNonQuery();
                        if (rowsAffected >= 1)
                        {
                            Command.Transaction.Commit();
                            status = true;
                        }
                        else
                        {
                            Command.Transaction.Rollback();
                        }
                    }
                }
            }
         }