// Comprehensive .NET Unit Test Template - Auto-Generated with xUnit
// This template generates complete unit tests for .NET backend components
using Xunit;
using Moq;
using FluentAssertions;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Microsoft.AspNetCore.Http;
using {{NAMESPACE}}.Controllers;
using {{NAMESPACE}}.Services;
using {{NAMESPACE}}.Models;
using {{NAMESPACE}}.DTOs;
using {{NAMESPACE}}.Repositories;
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Security.Claims;
using System.ComponentModel.DataAnnotations;
namespace {{NAMESPACE}}.Tests.Controllers
{
///
/// Comprehensive unit tests for {{CONTROLLER_NAME}}
/// Generated automatically by Hubtel Test Engineer
///
public class {{CONTROLLER_NAME}}Tests : IDisposable
{
#region Test Setup and Data
private readonly Mock<{{SERVICE_INTERFACE}}> _mockService;
private readonly Mock> _mockLogger;
private readonly {{CONTROLLER_NAME}} _controller;
private readonly Mock _mockHttpContext;
// Test data factory with comprehensive scenarios
private static class TestDataFactory
{
public static readonly {{ENTITY_TYPE}} ValidEntity = new {{ENTITY_TYPE}}
{
{{#each VALID_ENTITY_PROPERTIES}}
{{this.name}} = {{this.value}},
{{/each}}
};
public static readonly {{ENTITY_TYPE}} InvalidEntity = new {{ENTITY_TYPE}}
{
{{#each INVALID_ENTITY_PROPERTIES}}
{{this.name}} = {{this.value}}, // {{this.reason}}
{{/each}}
};
public static readonly {{DTO_TYPE}} ValidDto = new {{DTO_TYPE}}
{
{{#each VALID_DTO_PROPERTIES}}
{{this.name}} = {{this.value}},
{{/each}}
};
public static readonly List<{{ENTITY_TYPE}}> EntityCollection = new List<{{ENTITY_TYPE}}>
{
ValidEntity,
new {{ENTITY_TYPE}} { {{#each ADDITIONAL_ENTITIES}}{{this.prop}} = {{this.value}}, {{/each}} },
};
// Edge case test data
public static readonly object[] BoundaryValues = new object[]
{
{{#each BOUNDARY_VALUES}}
{{this.value}}, // {{this.description}}
{{/each}}
};
// Malicious input test data
public static readonly string[] MaliciousInputs = new string[]
{
"",
"'; DROP TABLE {{ENTITY_TYPE}}s; --",
"../../etc/passwd",
"{{REPEATED_CHARACTER_1000}}",
"\0\0\0null_bytes\0\0\0"
};
}
public {{CONTROLLER_NAME}}Tests()
{
_mockService = new Mock<{{SERVICE_INTERFACE}}>();
_mockLogger = new Mock>();
_mockHttpContext = new Mock();
_controller = new {{CONTROLLER_NAME}}(_mockService.Object, _mockLogger.Object)
{
ControllerContext = new ControllerContext
{
HttpContext = _mockHttpContext.Object
}
};
SetupDefaultMocks();
}
private void SetupDefaultMocks()
{
var claims = new List
{
new Claim(ClaimTypes.NameIdentifier, "test-user-id"),
new Claim(ClaimTypes.Name, "test-user"),
new Claim(ClaimTypes.Role, "User")
};
var identity = new ClaimsIdentity(claims, "TestAuth");
var principal = new ClaimsPrincipal(identity);
_mockHttpContext.Setup(c => c.User).Returns(principal);
}
public void Dispose()
{
_controller?.Dispose();
_mockService?.Reset();
_mockLogger?.Reset();
_mockHttpContext?.Reset();
}
#endregion
#region Constructor Tests
[Fact]
public void Constructor_WithNullService_ThrowsArgumentNullException()
{
// Act & Assert
var exception = Assert.Throws(() =>
new {{CONTROLLER_NAME}}(null, _mockLogger.Object));
exception.ParamName.Should().Be("{{SERVICE_PARAMETER_NAME}}");
}
[Fact]
public void Constructor_WithNullLogger_ThrowsArgumentNullException()
{
// Act & Assert
var exception = Assert.Throws(() =>
new {{CONTROLLER_NAME}}(_mockService.Object, null));
exception.ParamName.Should().Be("logger");
}
[Fact]
public void Constructor_WithValidDependencies_InitializesCorrectly()
{
// Act
var controller = new {{CONTROLLER_NAME}}(_mockService.Object, _mockLogger.Object);
// Assert
controller.Should().NotBeNull();
controller.Should().BeAssignableTo();
}
#endregion
{{#each CONTROLLER_ACTIONS}}
#region {{this.name}} Action Tests
[Fact]
public async Task {{this.name}}_WithValidInput_ReturnsOkResult()
{
// Arrange
var input = TestDataFactory.ValidDto;
var expectedResult = TestDataFactory.ValidEntity;
_mockService.Setup(s => s.{{this.serviceMethod}}(It.IsAny<{{this.inputType}}>()))
.ReturnsAsync(expectedResult);
// Act
var result = await _controller.{{this.name}}(input);
// Assert
result.Should().BeOfType();
var okResult = (OkObjectResult)result;
okResult.Value.Should().BeEquivalentTo(expectedResult);
okResult.StatusCode.Should().Be(200);
_mockService.Verify(s => s.{{this.serviceMethod}}(
It.Is<{{this.inputType}}>(x => x.Equals(input))), Times.Once);
}
[Fact]
public async Task {{this.name}}_WithNullInput_ReturnsBadRequest()
{
// Act
var result = await _controller.{{this.name}}(null);
// Assert
result.Should().BeOfType();
var badRequestResult = (BadRequestObjectResult)result;
badRequestResult.StatusCode.Should().Be(400);
badRequestResult.Value.Should().NotBeNull();
}
[Fact]
public async Task {{this.name}}_WithInvalidModelState_ReturnsBadRequest()
{
// Arrange
var invalidInput = TestDataFactory.InvalidEntity;
_controller.ModelState.AddModelError("{{this.primaryProperty}}", "{{this.validationError}}");
// Act
var result = await _controller.{{this.name}}(invalidInput);
// Assert
result.Should().BeOfType();
var badRequestResult = (BadRequestObjectResult)result;
badRequestResult.StatusCode.Should().Be(400);
// Verify service was not called
_mockService.Verify(s => s.{{this.serviceMethod}}(It.IsAny<{{this.inputType}}>()), Times.Never);
}
[Theory]
[MemberData(nameof(GetInvalidInputTestData))]
public async Task {{this.name}}_WithVariousInvalidInputs_ReturnsBadRequest(
{{this.inputType}} invalidInput,
string expectedErrorMessage)
{
// Act
var result = await _controller.{{this.name}}(invalidInput);
// Assert
result.Should().BeOfType();
var badRequestResult = (BadRequestObjectResult)result;
badRequestResult.Value.ToString().Should().Contain(expectedErrorMessage);
}
[Fact]
public async Task {{this.name}}_ServiceThrowsArgumentException_ReturnsBadRequest()
{
// Arrange
var input = TestDataFactory.ValidDto;
var exceptionMessage = "Invalid argument provided to service";
_mockService.Setup(s => s.{{this.serviceMethod}}(It.IsAny<{{this.inputType}}>()))
.ThrowsAsync(new ArgumentException(exceptionMessage));
// Act
var result = await _controller.{{this.name}}(input);
// Assert
result.Should().BeOfType();
var badRequestResult = (BadRequestObjectResult)result;
badRequestResult.Value.ToString().Should().Contain(exceptionMessage);
// Verify error was logged
VerifyErrorLogged(exceptionMessage, LogLevel.Warning);
}
[Fact]
public async Task {{this.name}}_ServiceThrowsUnauthorizedAccessException_ReturnsUnauthorized()
{
// Arrange
var input = TestDataFactory.ValidDto;
var exceptionMessage = "User not authorized for this operation";
_mockService.Setup(s => s.{{this.serviceMethod}}(It.IsAny<{{this.inputType}}>()))
.ThrowsAsync(new UnauthorizedAccessException(exceptionMessage));
// Act
var result = await _controller.{{this.name}}(input);
// Assert
result.Should().BeOfType();
var unauthorizedResult = (UnauthorizedObjectResult)result;
unauthorizedResult.StatusCode.Should().Be(401);
}
{{#if this.returnsEntity}}
[Fact]
public async Task {{this.name}}_EntityNotFound_ReturnsNotFound()
{
// Arrange
var input = TestDataFactory.ValidDto;
_mockService.Setup(s => s.{{this.serviceMethod}}(It.IsAny<{{this.inputType}}>()))
.ReturnsAsync(({{this.returnType}})null);
// Act
var result = await _controller.{{this.name}}(input);
// Assert
result.Should().BeOfType();
var notFoundResult = (NotFoundObjectResult)result;
notFoundResult.StatusCode.Should().Be(404);
}
{{/if}}
[Fact]
public async Task {{this.name}}_ServiceThrowsTimeoutException_ReturnsRequestTimeout()
{
// Arrange
var input = TestDataFactory.ValidDto;
_mockService.Setup(s => s.{{this.serviceMethod}}(It.IsAny<{{this.inputType}}>()))
.ThrowsAsync(new TimeoutException("Operation timed out"));
// Act
var result = await _controller.{{this.name}}(input);
// Assert
result.Should().BeOfType();
var objectResult = (ObjectResult)result;
objectResult.StatusCode.Should().Be(408); // Request Timeout
}
[Fact]
public async Task {{this.name}}_ServiceThrowsUnexpectedException_ReturnsInternalServerError()
{
// Arrange
var input = TestDataFactory.ValidDto;
var exception = new InvalidOperationException("Unexpected service error");
_mockService.Setup(s => s.{{this.serviceMethod}}(It.IsAny<{{this.inputType}}>()))
.ThrowsAsync(exception);
// Act
var result = await _controller.{{this.name}}(input);
// Assert
result.Should().BeOfType();
var objectResult = (ObjectResult)result;
objectResult.StatusCode.Should().Be(500);
// Verify critical error was logged
VerifyErrorLogged("Unexpected service error", LogLevel.Error);
}
{{#if this.hasConcurrencyHandling}}
[Fact]
public async Task {{this.name}}_ConcurrencyConflict_ReturnsConflict()
{
// Arrange
var input = TestDataFactory.ValidDto;
_mockService.Setup(s => s.{{this.serviceMethod}}(It.IsAny<{{this.inputType}}>()))
.ThrowsAsync(new InvalidOperationException("Concurrency conflict detected"));
// Act
var result = await _controller.{{this.name}}(input);
// Assert
result.Should().BeOfType();
var conflictResult = (ConflictObjectResult)result;
conflictResult.StatusCode.Should().Be(409);
}
{{/if}}
{{#if this.hasRateLimiting}}
[Fact]
public async Task {{this.name}}_RateLimitExceeded_ReturnsTooManyRequests()
{
// Arrange
var input = TestDataFactory.ValidDto;
_mockService.Setup(s => s.{{this.serviceMethod}}(It.IsAny<{{this.inputType}}>()))
.ThrowsAsync(new InvalidOperationException("Rate limit exceeded"));
// Act
var result = await _controller.{{this.name}}(input);
// Assert
result.Should().BeOfType();
var objectResult = (ObjectResult)result;
objectResult.StatusCode.Should().Be(429); // Too Many Requests
}
{{/if}}
[Fact]
public async Task {{this.name}}_SuccessfulExecution_LogsInformation()
{
// Arrange
var input = TestDataFactory.ValidDto;
var expectedResult = TestDataFactory.ValidEntity;
_mockService.Setup(s => s.{{this.serviceMethod}}(It.IsAny<{{this.inputType}}>()))
.ReturnsAsync(expectedResult);
// Act
await _controller.{{this.name}}(input);
// Assert
VerifyInformationLogged("{{this.name}} executed successfully");
}
public static IEnumerable