UNPKG

cqt-agent

Version:
604 lines (494 loc) 21.4 kB
# Unit Test Generator ## ⚠️ CRITICAL EXECUTION NOTICE ⚠️ **THIS IS AN EXECUTABLE WORKFLOW - NOT REFERENCE MATERIAL** When this task is invoked: 1. **CODE ANALYSIS** - Analyze source code structure, dependencies, and logic flows 2. **TEST CASE GENERATION** - Create comprehensive test cases covering all scenarios 3. **FRAMEWORK-SPECIFIC IMPLEMENTATION** - Generate tests using appropriate testing frameworks 4. **QUALITY VALIDATION** - Ensure tests follow best practices and achieve high coverage ## Overview This workflow analyzes source code and generates high-quality unit tests using the appropriate testing framework for the technology stack. It creates comprehensive test suites covering normal cases, edge cases, and error scenarios. ## Input Parameters ### Required Parameters - **file_path**: Absolute path to the source file to test - **test_framework**: "vitest" | "jest" | "nunit" | "auto-detect" ### Optional Parameters - **coverage_target**: number (default: 90) - **include_edge_cases**: boolean (default: true) - **mock_dependencies**: boolean (default: true) - **generate_integration_helpers**: boolean (default: true) - **accessibility_tests**: boolean (default: true for components) ## Test Generation Framework ### Phase 1: Source Code Analysis ```yaml step: analyze_source_code description: Comprehensive analysis of source code to understand structure and behavior code_analysis: - structure_analysis: - function_identification: Extract all functions, methods, and exports - dependency_mapping: Map imports, external dependencies, and internal modules - type_analysis: Analyze TypeScript types, interfaces, and props - complexity_assessment: Evaluate cyclomatic complexity and edge cases - behavior_analysis: - input_output_mapping: Identify function inputs and expected outputs - side_effect_detection: Find state mutations, API calls, DOM manipulation - error_conditions: Identify potential error scenarios and exceptions - async_patterns: Detect promises, async/await, callbacks - framework_detection: - component_analysis: React/Vue component props, state, lifecycle - service_analysis: Business logic, data processing, API services - utility_analysis: Pure functions, helpers, transformations - hook_analysis: Custom hooks, state management patterns ``` ### Phase 2: Test Case Design ```yaml step: design_test_cases description: Create comprehensive test scenarios covering all code paths test_case_design: - happy_path_scenarios: - normal_inputs: Standard use cases with expected inputs - typical_workflows: Common user interactions and data flows - success_conditions: Verify correct behavior under normal conditions - expected_outputs: Validate return values and side effects - edge_case_scenarios: - boundary_conditions: Min/max values, empty/null inputs - unusual_inputs: Special characters, extreme values, type mismatches - state_transitions: Component lifecycle, state changes - timing_conditions: Race conditions, delayed responses - error_scenarios: - invalid_inputs: Malformed data, wrong types, missing parameters - network_failures: API errors, timeout conditions - permission_errors: Authentication, authorization failures - system_errors: Out of memory, file system issues - integration_scenarios: - dependency_interactions: How component interacts with dependencies - event_handling: User events, system events, custom events - data_flow_testing: Props down, events up patterns - context_usage: React Context, global state interactions ``` ### Phase 3: Mock Strategy Development ```yaml step: develop_mocking_strategy description: Create comprehensive mocking strategy for dependencies and external services mocking_strategy: - dependency_mocking: - external_apis: HTTP clients, REST services, GraphQL - database_access: ORMs, query builders, direct DB connections - file_system: File operations, configuration loading - third_party_libraries: Payment gateways, analytics, notifications - component_mocking: - child_components: Mock complex child components - custom_hooks: Mock custom hook implementations - context_providers: Mock React Context providers - higher_order_components: Mock HOC wrapping - service_mocking: - business_services: Core business logic services - utility_services: Logging, caching, validation - infrastructure_services: Message queues, event buses - configuration_services: Environment, feature flags ``` ### Phase 4: Test Implementation Generation ```yaml step: generate_test_implementation description: Generate framework-specific test implementations with best practices implementation_generation: - test_structure: - describe_blocks: Logical grouping of related tests - test_organization: Clear naming and categorization - setup_teardown: Proper before/after hooks - test_isolation: Independent test execution - assertion_patterns: - behavior_assertions: Verify actual behavior vs expected - state_assertions: Check component/service state changes - interaction_assertions: Verify function calls and parameters - output_assertions: Validate return values and side effects - framework_specific: - vitest_patterns: Vitest-specific utilities and matchers - testing_library: Component testing with user events - nunit_patterns: .NET testing patterns and attributes - async_testing: Promise/async handling patterns ``` ## Framework-Specific Implementation ### Vitest/React Component Tests ```typescript // Generated test for React component import { render, screen, fireEvent, waitFor } from '@testing-library/react' import { vi, describe, it, expect, beforeEach } from 'vitest' import { UserDashboard } from '../UserDashboard' import { useAuth } from '../hooks/useAuth' import { fetchUserData } from '../services/userService' // Mock dependencies vi.mock('../hooks/useAuth') vi.mock('../services/userService') const mockUseAuth = vi.mocked(useAuth) const mockFetchUserData = vi.mocked(fetchUserData) describe('UserDashboard', () => { const defaultProps = { userId: 'user123', onUserUpdate: vi.fn(), theme: 'light' } beforeEach(() => { vi.clearAllMocks() mockUseAuth.mockReturnValue({ user: { id: 'user123', name: 'John Doe', role: 'user' }, isAuthenticated: true, loading: false }) }) describe('Rendering', () => { it('should render user dashboard with user information', () => { render(<UserDashboard {...defaultProps} />) expect(screen.getByText('Welcome, John Doe')).toBeInTheDocument() expect(screen.getByRole('main')).toHaveAttribute('aria-label', 'User Dashboard') }) it('should show loading state when user data is loading', () => { mockUseAuth.mockReturnValue({ user: null, isAuthenticated: true, loading: true }) render(<UserDashboard {...defaultProps} />) expect(screen.getByRole('progressbar')).toBeInTheDocument() expect(screen.getByText('Loading dashboard...')).toBeInTheDocument() }) it('should handle unauthenticated state', () => { mockUseAuth.mockReturnValue({ user: null, isAuthenticated: false, loading: false }) render(<UserDashboard {...defaultProps} />) expect(screen.getByText('Please log in to access your dashboard')).toBeInTheDocument() }) }) describe('User Interactions', () => { it('should call onUserUpdate when profile is edited', async () => { render(<UserDashboard {...defaultProps} />) const editButton = screen.getByRole('button', { name: /edit profile/i }) fireEvent.click(editButton) const nameInput = screen.getByLabelText(/name/i) fireEvent.change(nameInput, { target: { value: 'Jane Doe' } }) const saveButton = screen.getByRole('button', { name: /save/i }) fireEvent.click(saveButton) await waitFor(() => { expect(defaultProps.onUserUpdate).toHaveBeenCalledWith({ id: 'user123', name: 'Jane Doe', role: 'user' }) }) }) it('should handle keyboard navigation', () => { render(<UserDashboard {...defaultProps} />) const dashboard = screen.getByRole('main') fireEvent.keyDown(dashboard, { key: 'Tab' }) expect(screen.getByRole('button', { name: /edit profile/i })).toHaveFocus() }) }) describe('Data Fetching', () => { it('should fetch user data on mount', async () => { mockFetchUserData.mockResolvedValue({ profile: { avatar: 'avatar.jpg', preferences: {} }, stats: { loginCount: 42 } }) render(<UserDashboard {...defaultProps} />) expect(mockFetchUserData).toHaveBeenCalledWith('user123') await waitFor(() => { expect(screen.getByText('Login Count: 42')).toBeInTheDocument() }) }) it('should handle fetch errors gracefully', async () => { mockFetchUserData.mockRejectedValue(new Error('Network error')) render(<UserDashboard {...defaultProps} />) await waitFor(() => { expect(screen.getByText('Unable to load dashboard data')).toBeInTheDocument() }) }) }) describe('Accessibility', () => { it('should have proper ARIA labels and roles', () => { render(<UserDashboard {...defaultProps} />) expect(screen.getByRole('main')).toHaveAttribute('aria-label', 'User Dashboard') expect(screen.getByRole('button', { name: /edit profile/i })).toBeInTheDocument() expect(screen.getByLabelText(/user statistics/i)).toBeInTheDocument() }) it('should announce loading state to screen readers', () => { mockUseAuth.mockReturnValue({ user: null, isAuthenticated: true, loading: true }) render(<UserDashboard {...defaultProps} />) expect(screen.getByRole('progressbar')).toHaveAttribute('aria-label', 'Loading dashboard') }) }) describe('Error Boundaries', () => { it('should handle component errors gracefully', () => { const ThrowingComponent = () => { throw new Error('Test error') } const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => {}) expect(() => { render( <UserDashboard {...defaultProps}> <ThrowingComponent /> </UserDashboard> ) }).not.toThrow() consoleSpy.mockRestore() }) }) }) ``` ### NUnit/.NET Service Tests ```csharp // Generated test for .NET service using NUnit.Framework; using Moq; using FluentAssertions; using Microsoft.Extensions.Logging; using Hubtel.Services; using Hubtel.Models; using Hubtel.Exceptions; namespace Hubtel.Tests.Services { [TestFixture] public class PaymentServiceTests { private Mock<IPaymentGateway> _mockPaymentGateway; private Mock<IUserRepository> _mockUserRepository; private Mock<ILogger<PaymentService>> _mockLogger; private PaymentService _paymentService; [SetUp] public void Setup() { _mockPaymentGateway = new Mock<IPaymentGateway>(); _mockUserRepository = new Mock<IUserRepository>(); _mockLogger = new Mock<ILogger<PaymentService>>(); _paymentService = new PaymentService( _mockPaymentGateway.Object, _mockUserRepository.Object, _mockLogger.Object ); } [TearDown] public void TearDown() { _paymentService?.Dispose(); } [TestFixture] public class ProcessPaymentMethod : PaymentServiceTests { private PaymentRequest _validPaymentRequest; private User _validUser; [SetUp] public void ProcessPaymentSetup() { _validPaymentRequest = new PaymentRequest { UserId = "user123", Amount = 100.00m, Currency = "USD", PaymentMethod = "credit_card", Description = "Test payment" }; _validUser = new User { Id = "user123", Email = "test@example.com", IsActive = true, PaymentMethodsEnabled = true }; } [Test] public async Task ProcessPayment_WithValidRequest_ShouldReturnSuccessResult() { // Arrange _mockUserRepository .Setup(x => x.GetByIdAsync("user123")) .ReturnsAsync(_validUser); _mockPaymentGateway .Setup(x => x.ProcessPaymentAsync(It.IsAny<PaymentRequest>())) .ReturnsAsync(new PaymentResult { Success = true, TransactionId = "txn123", Status = PaymentStatus.Completed }); // Act var result = await _paymentService.ProcessPaymentAsync(_validPaymentRequest); // Assert result.Should().NotBeNull(); result.Success.Should().BeTrue(); result.TransactionId.Should().NotBeNullOrEmpty(); result.Status.Should().Be(PaymentStatus.Completed); } [Test] public async Task ProcessPayment_WithInvalidUser_ShouldThrowUserNotFoundException() { // Arrange _mockUserRepository .Setup(x => x.GetByIdAsync("invalid_user")) .ReturnsAsync((User)null); var invalidRequest = _validPaymentRequest with { UserId = "invalid_user" }; // Act & Assert var exception = await Assert.ThrowsAsync<UserNotFoundException>( () => _paymentService.ProcessPaymentAsync(invalidRequest) ); exception.UserId.Should().Be("invalid_user"); exception.Message.Should().Contain("User not found"); } [TestCase(0)] [TestCase(-10)] [TestCase(-100.50)] public async Task ProcessPayment_WithInvalidAmount_ShouldThrowInvalidPaymentException(decimal invalidAmount) { // Arrange var invalidRequest = _validPaymentRequest with { Amount = invalidAmount }; _mockUserRepository .Setup(x => x.GetByIdAsync("user123")) .ReturnsAsync(_validUser); // Act & Assert var exception = await Assert.ThrowsAsync<InvalidPaymentException>( () => _paymentService.ProcessPaymentAsync(invalidRequest) ); exception.Message.Should().Contain("Amount must be greater than zero"); } [Test] public async Task ProcessPayment_WithInactiveUser_ShouldThrowUserNotActiveException() { // Arrange var inactiveUser = _validUser with { IsActive = false }; _mockUserRepository .Setup(x => x.GetByIdAsync("user123")) .ReturnsAsync(inactiveUser); // Act & Assert var exception = await Assert.ThrowsAsync<UserNotActiveException>( () => _paymentService.ProcessPaymentAsync(_validPaymentRequest) ); exception.UserId.Should().Be("user123"); } [Test] public async Task ProcessPayment_WhenGatewayFails_ShouldReturnFailureResult() { // Arrange _mockUserRepository .Setup(x => x.GetByIdAsync("user123")) .ReturnsAsync(_validUser); _mockPaymentGateway .Setup(x => x.ProcessPaymentAsync(It.IsAny<PaymentRequest>())) .ReturnsAsync(new PaymentResult { Success = false, ErrorCode = "GATEWAY_ERROR", ErrorMessage = "Payment gateway unavailable" }); // Act var result = await _paymentService.ProcessPaymentAsync(_validPaymentRequest); // Assert result.Should().NotBeNull(); result.Success.Should().BeFalse(); result.ErrorCode.Should().Be("GATEWAY_ERROR"); result.ErrorMessage.Should().Contain("gateway unavailable"); } [Test] public async Task ProcessPayment_ShouldLogPaymentAttempt() { // Arrange _mockUserRepository .Setup(x => x.GetByIdAsync("user123")) .ReturnsAsync(_validUser); _mockPaymentGateway .Setup(x => x.ProcessPaymentAsync(It.IsAny<PaymentRequest>())) .ReturnsAsync(new PaymentResult { Success = true, TransactionId = "txn123" }); // Act await _paymentService.ProcessPaymentAsync(_validPaymentRequest); // Assert _mockLogger.Verify( x => x.Log( LogLevel.Information, It.IsAny<EventId>(), It.Is<It.IsAnyType>((v, t) => v.ToString().Contains("Processing payment for user")), It.IsAny<Exception>(), It.IsAny<Func<It.IsAnyType, Exception, string>>() ), Times.Once ); } } [TestFixture] public class ValidatePaymentRequestMethod : PaymentServiceTests { [Test] public void ValidatePaymentRequest_WithValidRequest_ShouldNotThrow() { // Arrange var validRequest = new PaymentRequest { UserId = "user123", Amount = 50.00m, Currency = "USD", PaymentMethod = "credit_card" }; // Act & Assert Assert.DoesNotThrow(() => _paymentService.ValidatePaymentRequest(validRequest)); } [TestCase(null)] [TestCase("")] [TestCase(" ")] public void ValidatePaymentRequest_WithInvalidUserId_ShouldThrowArgumentException(string invalidUserId) { // Arrange var invalidRequest = new PaymentRequest { UserId = invalidUserId, Amount = 50.00m, Currency = "USD", PaymentMethod = "credit_card" }; // Act & Assert var exception = Assert.Throws<ArgumentException>( () => _paymentService.ValidatePaymentRequest(invalidRequest) ); exception.Message.Should().Contain("UserId cannot be null or empty"); } [TestCase("INVALID")] [TestCase("123")] [TestCase("")] public void ValidatePaymentRequest_WithInvalidCurrency_ShouldThrowArgumentException(string invalidCurrency) { // Arrange var invalidRequest = new PaymentRequest { UserId = "user123", Amount = 50.00m, Currency = invalidCurrency, PaymentMethod = "credit_card" }; // Act & Assert var exception = Assert.Throws<ArgumentException>( () => _paymentService.ValidatePaymentRequest(invalidRequest) ); exception.Message.Should().Contain("Invalid currency code"); } } } } ``` ## Quality Validation ### Test Quality Checklist - ✅ **AAA Pattern**: Arrange, Act, Assert structure - ✅ **Descriptive Names**: Clear test method and describe block names - ✅ **Single Responsibility**: Each test validates one specific behavior - ✅ **Test Isolation**: Tests can run independently in any order - ✅ **Proper Mocking**: Dependencies are properly mocked and verified - ✅ **Edge Cases**: Boundary conditions and error scenarios covered - ✅ **Accessibility**: Components tested for a11y compliance - ✅ **Async Handling**: Promises and async operations properly tested ### Coverage Validation - **Line Coverage**: Target 90%+ for generated tests - **Branch Coverage**: All conditional paths tested - **Function Coverage**: All exported functions tested - **Statement Coverage**: All executable statements covered This comprehensive unit test generator creates high-quality, maintainable tests that follow best practices and achieve excellent coverage across different testing frameworks.