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);
}
}