From 193a2078b35bf0ed2f7846b5687fb2a02e5b05da Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 15 Nov 2025 13:26:22 +0000 Subject: [PATCH 1/3] Initial plan From 97468c42336a194cf16b7ecc03040b7bb39ab5a1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 15 Nov 2025 13:38:15 +0000 Subject: [PATCH 2/3] Add comprehensive unit tests for add course feature Co-authored-by: Hemavathi15sg <224925058+Hemavathi15sg@users.noreply.github.com> --- .../CourseRegistration.API.Tests.csproj | 30 ++ api/CourseRegistration.API.Tests/UnitTest1.cs | 10 + ...ourseRegistration.Application.Tests.csproj | 29 ++ .../Services/CourseServiceTests.cs | 271 ++++++++++++++++++ .../CreateCourseDtoValidatorTests.cs | 129 +++++++++ api/CourseRegistration.sln | 28 ++ 6 files changed, 497 insertions(+) create mode 100644 api/CourseRegistration.API.Tests/CourseRegistration.API.Tests.csproj create mode 100644 api/CourseRegistration.API.Tests/UnitTest1.cs create mode 100644 api/CourseRegistration.Application.Tests/CourseRegistration.Application.Tests.csproj create mode 100644 api/CourseRegistration.Application.Tests/Services/CourseServiceTests.cs create mode 100644 api/CourseRegistration.Application.Tests/Validators/CreateCourseDtoValidatorTests.cs diff --git a/api/CourseRegistration.API.Tests/CourseRegistration.API.Tests.csproj b/api/CourseRegistration.API.Tests/CourseRegistration.API.Tests.csproj new file mode 100644 index 0000000..2dfae8b --- /dev/null +++ b/api/CourseRegistration.API.Tests/CourseRegistration.API.Tests.csproj @@ -0,0 +1,30 @@ + + + + net10.0 + enable + enable + false + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/CourseRegistration.API.Tests/UnitTest1.cs b/api/CourseRegistration.API.Tests/UnitTest1.cs new file mode 100644 index 0000000..0d806f1 --- /dev/null +++ b/api/CourseRegistration.API.Tests/UnitTest1.cs @@ -0,0 +1,10 @@ +namespace CourseRegistration.API.Tests; + +public class UnitTest1 +{ + [Fact] + public void Test1() + { + + } +} diff --git a/api/CourseRegistration.Application.Tests/CourseRegistration.Application.Tests.csproj b/api/CourseRegistration.Application.Tests/CourseRegistration.Application.Tests.csproj new file mode 100644 index 0000000..57fabec --- /dev/null +++ b/api/CourseRegistration.Application.Tests/CourseRegistration.Application.Tests.csproj @@ -0,0 +1,29 @@ + + + + net10.0 + enable + enable + false + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/api/CourseRegistration.Application.Tests/Services/CourseServiceTests.cs b/api/CourseRegistration.Application.Tests/Services/CourseServiceTests.cs new file mode 100644 index 0000000..cc8a84c --- /dev/null +++ b/api/CourseRegistration.Application.Tests/Services/CourseServiceTests.cs @@ -0,0 +1,271 @@ +using AutoMapper; +using CourseRegistration.Application.DTOs; +using CourseRegistration.Application.Services; +using CourseRegistration.Domain.Entities; +using CourseRegistration.Domain.Interfaces; +using FluentAssertions; +using Moq; +using Xunit; + +namespace CourseRegistration.Application.Tests.Services; + +/// +/// Unit tests for CourseService focusing on CreateCourseAsync functionality +/// +public class CourseServiceTests +{ + private readonly Mock _mockUnitOfWork; + private readonly Mock _mockMapper; + private readonly Mock _mockCourseRepository; + private readonly CourseService _courseService; + + public CourseServiceTests() + { + _mockUnitOfWork = new Mock(); + _mockMapper = new Mock(); + _mockCourseRepository = new Mock(); + + _mockUnitOfWork.Setup(u => u.Courses).Returns(_mockCourseRepository.Object); + + _courseService = new CourseService(_mockUnitOfWork.Object, _mockMapper.Object); + } + + [Fact] + public async Task CreateCourseAsync_WithValidData_ShouldCreateCourse() + { + // Arrange + var createCourseDto = new CreateCourseDto + { + CourseName = "Introduction to C#", + Description = "Learn the fundamentals of C# programming", + InstructorName = "John Doe", + StartDate = DateTime.UtcNow.AddDays(10), + EndDate = DateTime.UtcNow.AddDays(40), + Schedule = "MWF 10:00-11:30" + }; + + var course = new Course + { + CourseId = Guid.NewGuid(), + CourseName = createCourseDto.CourseName, + Description = createCourseDto.Description, + InstructorName = createCourseDto.InstructorName, + StartDate = createCourseDto.StartDate, + EndDate = createCourseDto.EndDate, + Schedule = createCourseDto.Schedule + }; + + var courseDto = new CourseDto + { + CourseId = course.CourseId, + CourseName = course.CourseName, + Description = course.Description, + InstructorName = course.InstructorName, + StartDate = course.StartDate, + EndDate = course.EndDate, + Schedule = course.Schedule + }; + + _mockMapper.Setup(m => m.Map(It.IsAny())).Returns(course); + _mockMapper.Setup(m => m.Map(It.IsAny())).Returns(courseDto); + _mockCourseRepository.Setup(r => r.AddAsync(It.IsAny())).ReturnsAsync(course); + _mockUnitOfWork.Setup(u => u.SaveChangesAsync()).ReturnsAsync(1); + + // Act + var result = await _courseService.CreateCourseAsync(createCourseDto); + + // Assert + result.Should().NotBeNull(); + result.CourseName.Should().Be(createCourseDto.CourseName); + result.Description.Should().Be(createCourseDto.Description); + result.InstructorName.Should().Be(createCourseDto.InstructorName); + result.StartDate.Should().Be(createCourseDto.StartDate); + result.EndDate.Should().Be(createCourseDto.EndDate); + result.Schedule.Should().Be(createCourseDto.Schedule); + + _mockCourseRepository.Verify(r => r.AddAsync(It.IsAny()), Times.Once); + _mockUnitOfWork.Verify(u => u.SaveChangesAsync(), Times.Once); + } + + [Fact] + public async Task CreateCourseAsync_WithStartDateInPast_ShouldThrowInvalidOperationException() + { + // Arrange + var createCourseDto = new CreateCourseDto + { + CourseName = "Introduction to C#", + Description = "Learn the fundamentals of C# programming", + InstructorName = "John Doe", + StartDate = DateTime.UtcNow.AddDays(-5), // Past date + EndDate = DateTime.UtcNow.AddDays(30), + Schedule = "MWF 10:00-11:30" + }; + + // Act & Assert + var exception = await Assert.ThrowsAsync( + () => _courseService.CreateCourseAsync(createCourseDto)); + + exception.Message.Should().Contain("must be in the future"); + + _mockCourseRepository.Verify(r => r.AddAsync(It.IsAny()), Times.Never); + _mockUnitOfWork.Verify(u => u.SaveChangesAsync(), Times.Never); + } + + [Fact] + public async Task CreateCourseAsync_WithEndDateBeforeStartDate_ShouldThrowInvalidOperationException() + { + // Arrange + var createCourseDto = new CreateCourseDto + { + CourseName = "Introduction to C#", + Description = "Learn the fundamentals of C# programming", + InstructorName = "John Doe", + StartDate = DateTime.UtcNow.AddDays(30), + EndDate = DateTime.UtcNow.AddDays(10), // Before start date + Schedule = "MWF 10:00-11:30" + }; + + // Act & Assert + var exception = await Assert.ThrowsAsync( + () => _courseService.CreateCourseAsync(createCourseDto)); + + exception.Message.Should().Contain("must be after start date"); + + _mockCourseRepository.Verify(r => r.AddAsync(It.IsAny()), Times.Never); + _mockUnitOfWork.Verify(u => u.SaveChangesAsync(), Times.Never); + } + + [Fact] + public async Task CreateCourseAsync_WithEndDateEqualToStartDate_ShouldThrowInvalidOperationException() + { + // Arrange + var startDate = DateTime.UtcNow.AddDays(10); + var createCourseDto = new CreateCourseDto + { + CourseName = "Introduction to C#", + Description = "Learn the fundamentals of C# programming", + InstructorName = "John Doe", + StartDate = startDate, + EndDate = startDate, // Same as start date + Schedule = "MWF 10:00-11:30" + }; + + // Act & Assert + var exception = await Assert.ThrowsAsync( + () => _courseService.CreateCourseAsync(createCourseDto)); + + exception.Message.Should().Contain("must be after start date"); + + _mockCourseRepository.Verify(r => r.AddAsync(It.IsAny()), Times.Never); + _mockUnitOfWork.Verify(u => u.SaveChangesAsync(), Times.Never); + } + + [Fact] + public async Task CreateCourseAsync_WithMinimalData_ShouldCreateCourse() + { + // Arrange + var createCourseDto = new CreateCourseDto + { + CourseName = "Short Course", + Description = null, // Optional field + InstructorName = "Jane Smith", + StartDate = DateTime.UtcNow.AddDays(7), + EndDate = DateTime.UtcNow.AddDays(14), + Schedule = "TTh 14:00-15:30" + }; + + var course = new Course + { + CourseId = Guid.NewGuid(), + CourseName = createCourseDto.CourseName, + Description = createCourseDto.Description, + InstructorName = createCourseDto.InstructorName, + StartDate = createCourseDto.StartDate, + EndDate = createCourseDto.EndDate, + Schedule = createCourseDto.Schedule + }; + + var courseDto = new CourseDto + { + CourseId = course.CourseId, + CourseName = course.CourseName, + Description = course.Description, + InstructorName = course.InstructorName, + StartDate = course.StartDate, + EndDate = course.EndDate, + Schedule = course.Schedule + }; + + _mockMapper.Setup(m => m.Map(It.IsAny())).Returns(course); + _mockMapper.Setup(m => m.Map(It.IsAny())).Returns(courseDto); + _mockCourseRepository.Setup(r => r.AddAsync(It.IsAny())).ReturnsAsync(course); + _mockUnitOfWork.Setup(u => u.SaveChangesAsync()).ReturnsAsync(1); + + // Act + var result = await _courseService.CreateCourseAsync(createCourseDto); + + // Assert + result.Should().NotBeNull(); + result.CourseName.Should().Be(createCourseDto.CourseName); + result.Description.Should().BeNull(); + + _mockCourseRepository.Verify(r => r.AddAsync(It.IsAny()), Times.Once); + _mockUnitOfWork.Verify(u => u.SaveChangesAsync(), Times.Once); + } + + [Fact] + public async Task CreateCourseAsync_ShouldGenerateNewCourseId() + { + // Arrange + var createCourseDto = new CreateCourseDto + { + CourseName = "Advanced C#", + Description = "Deep dive into C# features", + InstructorName = "Dr. Smith", + StartDate = DateTime.UtcNow.AddDays(15), + EndDate = DateTime.UtcNow.AddDays(60), + Schedule = "MWF 13:00-14:30" + }; + + var capturedCourse = (Course?)null; + + _mockMapper.Setup(m => m.Map(It.IsAny())) + .Returns((CreateCourseDto dto) => new Course + { + CourseId = Guid.NewGuid(), + CourseName = dto.CourseName, + Description = dto.Description, + InstructorName = dto.InstructorName, + StartDate = dto.StartDate, + EndDate = dto.EndDate, + Schedule = dto.Schedule + }); + + _mockCourseRepository.Setup(r => r.AddAsync(It.IsAny())) + .Callback(c => capturedCourse = c) + .ReturnsAsync((Course c) => c); + + _mockMapper.Setup(m => m.Map(It.IsAny())) + .Returns((Course c) => new CourseDto + { + CourseId = c.CourseId, + CourseName = c.CourseName, + Description = c.Description, + InstructorName = c.InstructorName, + StartDate = c.StartDate, + EndDate = c.EndDate, + Schedule = c.Schedule + }); + + _mockUnitOfWork.Setup(u => u.SaveChangesAsync()).ReturnsAsync(1); + + // Act + var result = await _courseService.CreateCourseAsync(createCourseDto); + + // Assert + result.Should().NotBeNull(); + result.CourseId.Should().NotBe(Guid.Empty); + capturedCourse.Should().NotBeNull(); + capturedCourse!.CourseId.Should().NotBe(Guid.Empty); + } +} diff --git a/api/CourseRegistration.Application.Tests/Validators/CreateCourseDtoValidatorTests.cs b/api/CourseRegistration.Application.Tests/Validators/CreateCourseDtoValidatorTests.cs new file mode 100644 index 0000000..0c0f7c1 --- /dev/null +++ b/api/CourseRegistration.Application.Tests/Validators/CreateCourseDtoValidatorTests.cs @@ -0,0 +1,129 @@ +using CourseRegistration.Application.DTOs; +using CourseRegistration.Application.Validators; +using FluentAssertions; +using Xunit; + +namespace CourseRegistration.Application.Tests.Validators; + +/// +/// Unit tests for CreateCourseDtoValidator +/// +public class CreateCourseDtoValidatorTests +{ + private readonly CreateCourseDtoValidator _validator; + + public CreateCourseDtoValidatorTests() + { + _validator = new CreateCourseDtoValidator(); + } + + [Fact] + public void Validate_WithValidDto_ShouldPass() + { + // Arrange + var dto = new CreateCourseDto + { + CourseName = "Introduction to C#", + Description = "Learn the fundamentals of C# programming", + InstructorName = "John Doe", + StartDate = DateTime.UtcNow.AddDays(10), + EndDate = DateTime.UtcNow.AddDays(40), + Schedule = "MWF 10:00-11:30" + }; + + // Act + var result = _validator.Validate(dto); + + // Assert + result.IsValid.Should().BeTrue(); + result.Errors.Should().BeEmpty(); + } + + [Fact] + public void Validate_WithEmptyCourseName_ShouldFail() + { + // Arrange + var dto = new CreateCourseDto + { + CourseName = "", + Description = "Description", + InstructorName = "John Doe", + StartDate = DateTime.UtcNow.AddDays(10), + EndDate = DateTime.UtcNow.AddDays(40), + Schedule = "MWF 10:00-11:30" + }; + + // Act + var result = _validator.Validate(dto); + + // Assert + result.IsValid.Should().BeFalse(); + result.Errors.Should().Contain(e => e.PropertyName == "CourseName" && e.ErrorMessage.Contains("required")); + } + + [Fact] + public void Validate_WithTooLongCourseName_ShouldFail() + { + // Arrange + var dto = new CreateCourseDto + { + CourseName = new string('A', 101), + Description = "Description", + InstructorName = "John Doe", + StartDate = DateTime.UtcNow.AddDays(10), + EndDate = DateTime.UtcNow.AddDays(40), + Schedule = "MWF 10:00-11:30" + }; + + // Act + var result = _validator.Validate(dto); + + // Assert + result.IsValid.Should().BeFalse(); + result.Errors.Should().Contain(e => e.PropertyName == "CourseName" && e.ErrorMessage.Contains("100 characters")); + } + + [Fact] + public void Validate_WithStartDateInPast_ShouldFail() + { + // Arrange + var dto = new CreateCourseDto + { + CourseName = "Valid Course", + Description = "Description", + InstructorName = "John Doe", + StartDate = DateTime.UtcNow.AddDays(-5), + EndDate = DateTime.UtcNow.AddDays(40), + Schedule = "MWF 10:00-11:30" + }; + + // Act + var result = _validator.Validate(dto); + + // Assert + result.IsValid.Should().BeFalse(); + result.Errors.Should().Contain(e => e.PropertyName == "StartDate" && e.ErrorMessage.Contains("future")); + } + + [Fact] + public void Validate_WithEndDateBeforeStartDate_ShouldFail() + { + // Arrange + var dto = new CreateCourseDto + { + CourseName = "Valid Course", + Description = "Description", + InstructorName = "John Doe", + StartDate = DateTime.UtcNow.AddDays(40), + EndDate = DateTime.UtcNow.AddDays(10), + Schedule = "MWF 10:00-11:30" + }; + + // Act + var result = _validator.Validate(dto); + + // Assert + result.IsValid.Should().BeFalse(); + result.Errors.Should().Contain(e => e.PropertyName == "EndDate" && e.ErrorMessage.Contains("after start date")); + } +} diff --git a/api/CourseRegistration.sln b/api/CourseRegistration.sln index 4bbe167..a527c94 100644 --- a/api/CourseRegistration.sln +++ b/api/CourseRegistration.sln @@ -11,6 +11,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CourseRegistration.Applicat EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CourseRegistration.Infrastructure", "CourseRegistration.Infrastructure\CourseRegistration.Infrastructure.csproj", "{234AB462-1115-42BF-ACC1-ED68930DD043}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CourseRegistration.Application.Tests", "CourseRegistration.Application.Tests\CourseRegistration.Application.Tests.csproj", "{BA79F6B1-5890-417E-9D48-C18AC5FAE920}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CourseRegistration.API.Tests", "CourseRegistration.API.Tests\CourseRegistration.API.Tests.csproj", "{CC45C3AB-4516-461C-A294-7A1EB7C8FDE9}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -69,6 +73,30 @@ Global {234AB462-1115-42BF-ACC1-ED68930DD043}.Release|x64.Build.0 = Release|Any CPU {234AB462-1115-42BF-ACC1-ED68930DD043}.Release|x86.ActiveCfg = Release|Any CPU {234AB462-1115-42BF-ACC1-ED68930DD043}.Release|x86.Build.0 = Release|Any CPU + {BA79F6B1-5890-417E-9D48-C18AC5FAE920}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BA79F6B1-5890-417E-9D48-C18AC5FAE920}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BA79F6B1-5890-417E-9D48-C18AC5FAE920}.Debug|x64.ActiveCfg = Debug|Any CPU + {BA79F6B1-5890-417E-9D48-C18AC5FAE920}.Debug|x64.Build.0 = Debug|Any CPU + {BA79F6B1-5890-417E-9D48-C18AC5FAE920}.Debug|x86.ActiveCfg = Debug|Any CPU + {BA79F6B1-5890-417E-9D48-C18AC5FAE920}.Debug|x86.Build.0 = Debug|Any CPU + {BA79F6B1-5890-417E-9D48-C18AC5FAE920}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BA79F6B1-5890-417E-9D48-C18AC5FAE920}.Release|Any CPU.Build.0 = Release|Any CPU + {BA79F6B1-5890-417E-9D48-C18AC5FAE920}.Release|x64.ActiveCfg = Release|Any CPU + {BA79F6B1-5890-417E-9D48-C18AC5FAE920}.Release|x64.Build.0 = Release|Any CPU + {BA79F6B1-5890-417E-9D48-C18AC5FAE920}.Release|x86.ActiveCfg = Release|Any CPU + {BA79F6B1-5890-417E-9D48-C18AC5FAE920}.Release|x86.Build.0 = Release|Any CPU + {CC45C3AB-4516-461C-A294-7A1EB7C8FDE9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {CC45C3AB-4516-461C-A294-7A1EB7C8FDE9}.Debug|Any CPU.Build.0 = Debug|Any CPU + {CC45C3AB-4516-461C-A294-7A1EB7C8FDE9}.Debug|x64.ActiveCfg = Debug|Any CPU + {CC45C3AB-4516-461C-A294-7A1EB7C8FDE9}.Debug|x64.Build.0 = Debug|Any CPU + {CC45C3AB-4516-461C-A294-7A1EB7C8FDE9}.Debug|x86.ActiveCfg = Debug|Any CPU + {CC45C3AB-4516-461C-A294-7A1EB7C8FDE9}.Debug|x86.Build.0 = Debug|Any CPU + {CC45C3AB-4516-461C-A294-7A1EB7C8FDE9}.Release|Any CPU.ActiveCfg = Release|Any CPU + {CC45C3AB-4516-461C-A294-7A1EB7C8FDE9}.Release|Any CPU.Build.0 = Release|Any CPU + {CC45C3AB-4516-461C-A294-7A1EB7C8FDE9}.Release|x64.ActiveCfg = Release|Any CPU + {CC45C3AB-4516-461C-A294-7A1EB7C8FDE9}.Release|x64.Build.0 = Release|Any CPU + {CC45C3AB-4516-461C-A294-7A1EB7C8FDE9}.Release|x86.ActiveCfg = Release|Any CPU + {CC45C3AB-4516-461C-A294-7A1EB7C8FDE9}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From db9219e0ca9c20d8d4c405f686aed62c254fbfc3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 15 Nov 2025 13:42:57 +0000 Subject: [PATCH 3/3] Add integration tests for add course API endpoint Co-authored-by: Hemavathi15sg <224925058+Hemavathi15sg@users.noreply.github.com> --- .../CoursesControllerIntegrationTests.cs | 117 ++++++++++++++++++ api/CourseRegistration.API.Tests/UnitTest1.cs | 10 -- api/CourseRegistration.API/Program.cs | 3 + 3 files changed, 120 insertions(+), 10 deletions(-) create mode 100644 api/CourseRegistration.API.Tests/Controllers/CoursesControllerIntegrationTests.cs delete mode 100644 api/CourseRegistration.API.Tests/UnitTest1.cs diff --git a/api/CourseRegistration.API.Tests/Controllers/CoursesControllerIntegrationTests.cs b/api/CourseRegistration.API.Tests/Controllers/CoursesControllerIntegrationTests.cs new file mode 100644 index 0000000..b343a82 --- /dev/null +++ b/api/CourseRegistration.API.Tests/Controllers/CoursesControllerIntegrationTests.cs @@ -0,0 +1,117 @@ +using System.Net; +using System.Net.Http.Json; +using System.Text.Json; +using CourseRegistration.Application.DTOs; +using FluentAssertions; +using Microsoft.AspNetCore.Mvc.Testing; +using Xunit; + +namespace CourseRegistration.API.Tests.Controllers; + +/// +/// Integration tests for CoursesController focusing on CreateCourse endpoint +/// +public class CoursesControllerIntegrationTests : IClassFixture> +{ + private readonly WebApplicationFactory _factory; + private readonly HttpClient _client; + + public CoursesControllerIntegrationTests(WebApplicationFactory factory) + { + _factory = factory; + _client = factory.CreateClient(); + } + + [Fact] + public async Task CreateCourse_WithValidData_ShouldReturn201Created() + { + // Arrange + var createCourseDto = new CreateCourseDto + { + CourseName = "Integration Test Course", + Description = "This is a test course created during integration testing", + InstructorName = "Dr. Test", + StartDate = DateTime.UtcNow.AddDays(30), + EndDate = DateTime.UtcNow.AddDays(60), + Schedule = "MWF 10:00-11:30" + }; + + // Act + var response = await _client.PostAsJsonAsync("/api/courses", createCourseDto); + + // Assert + response.StatusCode.Should().Be(HttpStatusCode.Created); + + var content = await response.Content.ReadAsStringAsync(); + content.Should().NotBeNullOrEmpty(); + + var apiResponse = JsonSerializer.Deserialize(content); + apiResponse.GetProperty("success").GetBoolean().Should().BeTrue(); + apiResponse.GetProperty("data").GetProperty("courseName").GetString().Should().Be(createCourseDto.CourseName); + } + + [Fact] + public async Task CreateCourse_WithStartDateInPast_ShouldReturn400BadRequest() + { + // Arrange + var createCourseDto = new CreateCourseDto + { + CourseName = "Invalid Course", + Description = "Course with past start date", + InstructorName = "Dr. Test", + StartDate = DateTime.UtcNow.AddDays(-5), + EndDate = DateTime.UtcNow.AddDays(30), + Schedule = "MWF 10:00-11:30" + }; + + // Act + var response = await _client.PostAsJsonAsync("/api/courses", createCourseDto); + + // Assert + response.StatusCode.Should().Be(HttpStatusCode.BadRequest); + } + + [Fact] + public async Task CreateCourse_WithEndDateBeforeStartDate_ShouldReturn400BadRequest() + { + // Arrange + var createCourseDto = new CreateCourseDto + { + CourseName = "Invalid Course", + Description = "Course with end date before start date", + InstructorName = "Dr. Test", + StartDate = DateTime.UtcNow.AddDays(60), + EndDate = DateTime.UtcNow.AddDays(30), + Schedule = "MWF 10:00-11:30" + }; + + // Act + var response = await _client.PostAsJsonAsync("/api/courses", createCourseDto); + + // Assert + response.StatusCode.Should().Be(HttpStatusCode.BadRequest); + } + + [Fact] + public async Task CreateCourse_ShouldReturnLocationHeader() + { + // Arrange + var createCourseDto = new CreateCourseDto + { + CourseName = "Location Header Test Course", + Description = "Testing location header", + InstructorName = "Dr. Location", + StartDate = DateTime.UtcNow.AddDays(30), + EndDate = DateTime.UtcNow.AddDays(60), + Schedule = "MWF 09:00-10:30" + }; + + // Act + var response = await _client.PostAsJsonAsync("/api/courses", createCourseDto); + + // Assert + response.StatusCode.Should().Be(HttpStatusCode.Created); + response.Headers.Location.Should().NotBeNull(); + response.Headers.Location!.ToString().Should().Contain("/api/Courses/"); + } +} diff --git a/api/CourseRegistration.API.Tests/UnitTest1.cs b/api/CourseRegistration.API.Tests/UnitTest1.cs deleted file mode 100644 index 0d806f1..0000000 --- a/api/CourseRegistration.API.Tests/UnitTest1.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace CourseRegistration.API.Tests; - -public class UnitTest1 -{ - [Fact] - public void Test1() - { - - } -} diff --git a/api/CourseRegistration.API/Program.cs b/api/CourseRegistration.API/Program.cs index 2c174da..377e494 100644 --- a/api/CourseRegistration.API/Program.cs +++ b/api/CourseRegistration.API/Program.cs @@ -299,3 +299,6 @@ static async Task SeedDatabase(CourseRegistrationDbContext context) Log.Information("Database seeded successfully with {StudentCount} students, {CourseCount} courses, and {RegistrationCount} registrations.", students.Length, courses.Length, registrations.Length); } + +// Make Program accessible for integration tests +public partial class Program { }