Implementing Unit Tests in C# with Moq Framework

Core Components of Unit Testing

Unit testing involves creating isolated tests for individual code components. The process includes setting up test projects, analyzing interface behaviors under various conditions, and providing appropriate input parameters.

3A Testing Pattern

The standard approach for structuring unit tests follows the Arrange-Act-Assert pattern:

  • Arrenge: Prepare test dependencies and inputs
  • Act: Execute the method under test
  • Assert: Verify expected outcomes

Example Controller Method

[HttpPost]
[Route("api/Account/GetEpVIPInfo")]
public object GetEpVIPInfo(GetEpVIPInfoRequest input)
{
    var response = new BaseResponse
    {
        Info = Constants.FailureMessage,
        Message = Constants.FailureMessage,
        Success = false,
        ResultCode = Constants.FailureCode
    };
    
    var vipDetail = new VIPDetailModel();
    var vipData = AccountService.GetEpVIPInfo(input);
    
    if (vipData != null)
    {
        vipDetail.VIPLevelId = DetermineVIPLevel(vipData.Name);
    }
    else
    {
        vipDetail.VIPLevelId = 0;
    }

    response = new BaseResponse
    {
        Info = vipDetail,
        Message = Constants.SuccessMessage,
        Success = true,
        ResultCode = Constants.SuccessCode
    };

    return response;
}

Corresponding Unit Tests

#region GetEpVIPInfo Tests

[TestMethod]
public void GetEpVIPInfo_InvalidParameters_ReturnsSuccessResponse()
{
    // Arrange
    var controller = new AccountController();
    var mockService = new Mock<IAccountService>();
    mockService.Setup(s => s.GetEpVIPInfo(It.IsAny<GetEpVIPInfoRequest>()))
               .Returns((VIPRecord)null);
    controller.AccountService = mockService.Object;

    // Act
    var testRequest = new GetEpVIPInfoRequest { CityCode = "3202", EnterpriseId = -1 };
    var testResult = controller.GetEpVIPInfo(testRequest);
    var responseData = testResult.GetResponseModel();

    // Assert
    Assert.IsTrue(responseData.Success);
    Assert.AreEqual(Constants.SuccessMessage, responseData.Message);
    Assert.AreEqual(Constants.SuccessCode, responseData.ResultCode);
}

[TestMethod]
public void GetEpVIPInfo_ValidParameters_ReturnsCorrectVIPData()
{
    // Arrange
    var controller = new AccountController();
    var mockService = new Mock<IAccountService>();
    mockService.Setup(s => s.GetEpVIPInfo(It.IsAny<GetEpVIPInfoRequest>()))
               .Returns(new VIPRecord { Name = "Monthly Member", Id = 4 });
    controller.AccountService = mockService.Object;

    // Act
    var testRequest = new GetEpVIPInfoRequest { CityCode = "3202", EnterpriseId = 1 };
    var testResult = controller.GetEpVIPInfo(testRequest);
    var responseData = testResult.GetResponseModel();

    var expectedDetail = new VIPDetailModel { VIPLevelId = 4 };

    // Assert
    Assert.IsTrue(responseData.Success);
    Assert.AreEqual(Constants.SuccessMessage, responseData.Message);
    Assert.AreEqual(Constants.SuccessCode, responseData.ResultCode);
    Assert.AreEqual(expectedDetail.ToJson(), responseData.Info.ToJson());
}

#endregion

Test Organization Practices

Using #region blocks helps organize test methods by functionality, making code navigation and maintenance more efficient. Each interface method should have tests covering all possible execution paths and edge cases.

Note: Paramter validation is handled at the interceptor level in this architecture, preventing null or missing parameter requests from reaching the controller methods.

Tags: C# Unit Testing Moq ASP.NET Test Methods

Posted on Fri, 15 May 2026 12:03:38 +0000 by ddragas