using System; using System.Collections.Generic; using System.Threading; using System.Threading.Tasks; using GermanApp.Application.DTOs; using GermanApp.Application.Services; using GermanApp.Presentation.Controllers; using Microsoft.AspNetCore.Mvc; using Microsoft.VisualStudio.TestTools.UnitTesting; using Moq; namespace GermanApp.Tests.Integration.Controllers; /// /// Integration tests for LessonsController. /// Tests controller behavior with mocked services. /// [TestClass] public class LessonsControllerTests { private Mock? _mockLessonService; private Mock? _mockProgressService; private LessonsController? _controller; [TestInitialize] public void TestInitialize() { _mockLessonService = new Mock(null!, null!); _mockProgressService = new Mock(null!, null!, null!); _controller = new LessonsController(_mockLessonService.Object, _mockProgressService.Object); } [TestCleanup] public void TestCleanup() { _controller = null; _mockLessonService = null; _mockProgressService = null; } private static DateTime TestDate => new DateTime(2024, 1, 1, 0, 0, 0, DateTimeKind.Utc); // ==================== GET ALL LESSONS TESTS ==================== [TestMethod] [TestCategory("LessonsController")] [TestCategory("GetAllLessons")] public async Task GetAllLessons_WithData_ReturnsOkWithLessons() { // Arrange var expectedLessons = new List { new LessonDto(1, "Greetings", "Learn basic greetings", 1, "A1", "Beginner A1", 1, "Vocabulary", TestDate, null), new LessonDto(2, "Introductions", "Learn to introduce yourself", 1, "A1", "Beginner A1", 2, "Vocabulary", TestDate, null) }; _mockLessonService!.Setup(s => s.GetAllLessonsAsync(It.IsAny())) .ReturnsAsync(expectedLessons); // Act var result = await _controller!.GetAllLessonsAsync(); // Assert Assert.IsInstanceOfType(result, typeof(OkObjectResult)); var okResult = result as OkObjectResult; Assert.IsNotNull(okResult); var returnedLessons = okResult.Value as IReadOnlyList; Assert.IsNotNull(returnedLessons); Assert.AreEqual(2, returnedLessons.Count); } [TestMethod] [TestCategory("LessonsController")] [TestCategory("GetAllLessons")] public async Task GetAllLessons_WithNoData_ReturnsEmptyList() { // Arrange var expectedLessons = new List(); _mockLessonService!.Setup(s => s.GetAllLessonsAsync(It.IsAny())) .ReturnsAsync(expectedLessons); // Act var result = await _controller!.GetAllLessonsAsync(); // Assert Assert.IsInstanceOfType(result, typeof(OkObjectResult)); var okResult = result as OkObjectResult; Assert.IsNotNull(okResult); var returnedLessons = okResult.Value as IReadOnlyList; Assert.IsNotNull(returnedLessons); Assert.AreEqual(0, returnedLessons.Count); } // ==================== GET LESSON BY ID TESTS ==================== [TestMethod] [TestCategory("LessonsController")] [TestCategory("GetLessonById")] public async Task GetLessonById_WithExistingId_ReturnsOkWithLesson() { // Arrange var expectedLesson = new LessonDto(1, "Greetings", "Learn basic greetings", 1, "A1", "Beginner A1", 1, "Vocabulary", TestDate, null); _mockLessonService!.Setup(s => s.GetLessonByIdAsync(1, It.IsAny())) .ReturnsAsync(expectedLesson); // Act var result = await _controller!.GetLessonByIdAsync(1); // Assert Assert.IsInstanceOfType(result, typeof(OkObjectResult)); var okResult = result as OkObjectResult; Assert.IsNotNull(okResult); var returnedLesson = okResult.Value as LessonDto; Assert.IsNotNull(returnedLesson); Assert.AreEqual(1, returnedLesson.Id); Assert.AreEqual("Greetings", returnedLesson.Title); } [TestMethod] [TestCategory("LessonsController")] [TestCategory("GetLessonById")] public async Task GetLessonById_WithNonExistingId_ReturnsNotFound() { // Arrange _mockLessonService!.Setup(s => s.GetLessonByIdAsync(999, It.IsAny())) .ReturnsAsync((LessonDto?)null); // Act var result = await _controller!.GetLessonByIdAsync(999); // Assert Assert.IsInstanceOfType(result, typeof(NotFoundResult)); } // ==================== GET LESSONS BY LEVEL TESTS ==================== [TestMethod] [TestCategory("LessonsController")] [TestCategory("GetLessonsByLevel")] public async Task GetLessonsByLevel_WithExistingLevel_ReturnsOkWithLessons() { // Arrange var expectedLessons = new List { new LessonDto(1, "Greetings", "Learn basic greetings", 1, "A1", "Beginner A1", 1, "Vocabulary", TestDate, null) }; _mockLessonService!.Setup(s => s.GetLessonsByLevelAsync(1, It.IsAny())) .ReturnsAsync(expectedLessons); // Act var result = await _controller!.GetLessonsByLevelAsync(1); // Assert Assert.IsInstanceOfType(result, typeof(OkObjectResult)); var okResult = result as OkObjectResult; Assert.IsNotNull(okResult); var returnedLessons = okResult.Value as IReadOnlyList; Assert.IsNotNull(returnedLessons); Assert.AreEqual(1, returnedLessons.Count); } [TestMethod] [TestCategory("LessonsController")] [TestCategory("GetLessonsByLevel")] public async Task GetLessonsByLevel_WithNonExistingLevel_ReturnsEmptyList() { // Arrange var expectedLessons = new List(); _mockLessonService!.Setup(s => s.GetLessonsByLevelAsync(999, It.IsAny())) .ReturnsAsync(expectedLessons); // Act var result = await _controller!.GetLessonsByLevelAsync(999); // Assert Assert.IsInstanceOfType(result, typeof(OkObjectResult)); var okResult = result as OkObjectResult; Assert.IsNotNull(okResult); var returnedLessons = okResult.Value as IReadOnlyList; Assert.IsNotNull(returnedLessons); Assert.AreEqual(0, returnedLessons.Count); } // ==================== CREATE LESSON TESTS ==================== [TestMethod] [TestCategory("LessonsController")] [TestCategory("CreateLesson")] public async Task CreateLesson_WithValidData_ReturnsCreatedAtAction() { // Arrange var createDto = new CreateLessonDto("Greetings", "Learn basic greetings", 1, 1, "Vocabulary"); var expectedLesson = new LessonDto(1, "Greetings", "Learn basic greetings", 1, "A1", "Beginner A1", 1, "Vocabulary", TestDate, null); _mockLessonService!.Setup(s => s.CreateLessonAsync(createDto, It.IsAny())) .ReturnsAsync(expectedLesson); // Act var result = await _controller!.CreateLessonAsync(createDto); // Assert Assert.IsInstanceOfType(result, typeof(CreatedAtActionResult)); var createdResult = result as CreatedAtActionResult; Assert.IsNotNull(createdResult); var returnedLesson = createdResult.Value as LessonDto; Assert.IsNotNull(returnedLesson); Assert.AreEqual(1, returnedLesson.Id); } // ==================== UPDATE LESSON TESTS ==================== [TestMethod] [TestCategory("LessonsController")] [TestCategory("UpdateLesson")] public async Task UpdateLesson_WithExistingId_ReturnsOkWithUpdatedLesson() { // Arrange var updateDto = new UpdateLessonDto("Updated Greetings", "Updated description", 1, 1, "Updated Topic"); var expectedLesson = new LessonDto(1, "Updated Greetings", "Updated description", 1, "A1", "Beginner A1", 1, "Updated Topic", TestDate, TestDate); _mockLessonService!.Setup(s => s.UpdateLessonAsync(1, updateDto, It.IsAny())) .ReturnsAsync(expectedLesson); // Act var result = await _controller!.UpdateLessonAsync(1, updateDto); // Assert Assert.IsInstanceOfType(result, typeof(OkObjectResult)); var okResult = result as OkObjectResult; Assert.IsNotNull(okResult); var returnedLesson = okResult.Value as LessonDto; Assert.IsNotNull(returnedLesson); Assert.AreEqual("Updated Greetings", returnedLesson.Title); } [TestMethod] [TestCategory("LessonsController")] [TestCategory("UpdateLesson")] public async Task UpdateLesson_WithNonExistingId_ReturnsNotFound() { // Arrange var updateDto = new UpdateLessonDto("Updated Greetings", "Updated description", 1, 1, "Updated Topic"); _mockLessonService!.Setup(s => s.UpdateLessonAsync(999, updateDto, It.IsAny())) .ReturnsAsync((LessonDto?)null); // Act var result = await _controller!.UpdateLessonAsync(999, updateDto); // Assert Assert.IsInstanceOfType(result, typeof(NotFoundResult)); } // ==================== DELETE LESSON TESTS ==================== [TestMethod] [TestCategory("LessonsController")] [TestCategory("DeleteLesson")] public async Task DeleteLesson_WithExistingId_ReturnsNoContent() { // Arrange _mockLessonService!.Setup(s => s.DeleteLessonAsync(1, It.IsAny())) .ReturnsAsync(true); // Act var result = await _controller!.DeleteLessonAsync(1); // Assert Assert.IsInstanceOfType(result, typeof(NoContentResult)); } [TestMethod] [TestCategory("LessonsController")] [TestCategory("DeleteLesson")] public async Task DeleteLesson_WithNonExistingId_ReturnsNotFound() { // Arrange _mockLessonService!.Setup(s => s.DeleteLessonAsync(999, It.IsAny())) .ReturnsAsync(false); // Act var result = await _controller!.DeleteLessonAsync(999); // Assert Assert.IsInstanceOfType(result, typeof(NotFoundResult)); } // ==================== GET FIRST LESSON IN LEVEL TESTS ==================== [TestMethod] [TestCategory("LessonsController")] [TestCategory("GetFirstLessonInLevel")] public async Task GetFirstLessonInLevel_WithExistingLevel_ReturnsOkWithLesson() { // Arrange var expectedLesson = new LessonDto(1, "Greetings", "Learn basic greetings", 1, "A1", "Beginner A1", 1, "Vocabulary", TestDate, null); _mockLessonService!.Setup(s => s.GetFirstLessonInLevelAsync(1, It.IsAny())) .ReturnsAsync(expectedLesson); // Act var result = await _controller!.GetFirstLessonInLevelAsync(1); // Assert Assert.IsInstanceOfType(result, typeof(OkObjectResult)); var okResult = result as OkObjectResult; Assert.IsNotNull(okResult); var returnedLesson = okResult.Value as LessonDto; Assert.IsNotNull(returnedLesson); Assert.AreEqual(1, returnedLesson.Order); } [TestMethod] [TestCategory("LessonsController")] [TestCategory("GetFirstLessonInLevel")] public async Task GetFirstLessonInLevel_WithNonExistingLevel_ReturnsNotFound() { // Arrange _mockLessonService!.Setup(s => s.GetFirstLessonInLevelAsync(999, It.IsAny())) .ReturnsAsync((LessonDto?)null); // Act var result = await _controller!.GetFirstLessonInLevelAsync(999); // Assert Assert.IsInstanceOfType(result, typeof(NotFoundResult)); } // ==================== IS NEXT LESSON UNLOCKED TESTS ==================== [TestMethod] [TestCategory("LessonsController")] [TestCategory("IsNextLessonUnlocked")] public async Task IsNextLessonUnlocked_WithCompletedPrevious_ReturnsTrue() { // Arrange _mockProgressService!.Setup(s => s.IsNextLessonUnlockedAsync(1, 1, It.IsAny())) .ReturnsAsync(true); // Act var result = await _controller!.IsNextLessonUnlockedAsync(1, 1); // Assert Assert.IsInstanceOfType(result, typeof(OkObjectResult)); var okResult = result as OkObjectResult; Assert.IsNotNull(okResult); Assert.AreEqual(true, okResult.Value); } [TestMethod] [TestCategory("LessonsController")] [TestCategory("IsNextLessonUnlocked")] public async Task IsNextLessonUnlocked_WithIncompletePrevious_ReturnsFalse() { // Arrange _mockProgressService!.Setup(s => s.IsNextLessonUnlockedAsync(1, 1, It.IsAny())) .ReturnsAsync(false); // Act var result = await _controller!.IsNextLessonUnlockedAsync(1, 1); // Assert Assert.IsInstanceOfType(result, typeof(OkObjectResult)); var okResult = result as OkObjectResult; Assert.IsNotNull(okResult); Assert.AreEqual(false, okResult.Value); } }