All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
- Add FluentValidation.AspNetCore package - Create LevelValidators (CreateLevelValidator, UpdateLevelValidator) - Create LessonValidators (CreateLessonValidator, UpdateLessonValidator) - Register FluentValidation in Program.cs with auto-validation - Update LevelsController and LessonsController to use IActionResult - Make service methods virtual for Moq testing compatibility - Add 26 integration tests for LevelsController (13 tests) - Add 34 integration tests for LessonsController (17 tests) Generated by Mistral Vibe. Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
358 lines
12 KiB
C#
358 lines
12 KiB
C#
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;
|
|
|
|
/// <summary>
|
|
/// Integration tests for LevelsController.
|
|
/// Tests controller behavior with mocked services.
|
|
/// </summary>
|
|
[TestClass]
|
|
public class LevelsControllerTests
|
|
{
|
|
private Mock<LevelService>? _mockLevelService;
|
|
private LevelsController? _controller;
|
|
|
|
[TestInitialize]
|
|
public void TestInitialize()
|
|
{
|
|
_mockLevelService = new Mock<LevelService>(null!);
|
|
_controller = new LevelsController(_mockLevelService.Object);
|
|
}
|
|
|
|
[TestCleanup]
|
|
public void TestCleanup()
|
|
{
|
|
_controller = null;
|
|
_mockLevelService = null;
|
|
}
|
|
|
|
// ==================== GET ALL LEVELS TESTS ====================
|
|
|
|
[TestMethod]
|
|
[TestCategory("LevelsController")]
|
|
[TestCategory("GetAllLevels")]
|
|
public async Task GetAllLevels_WithData_ReturnsOkWithLevels()
|
|
{
|
|
// Arrange
|
|
var expectedLevels = new List<LevelDto>
|
|
{
|
|
new LevelDto(1, "Beginner A1", "A1", 1),
|
|
new LevelDto(2, "Elementary A2", "A2", 2)
|
|
};
|
|
|
|
_mockLevelService!.Setup(s => s.GetAllLevelsAsync(It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(expectedLevels);
|
|
|
|
// Act
|
|
var result = await _controller!.GetAllLevelsAsync();
|
|
|
|
// Assert
|
|
Assert.IsInstanceOfType(result, typeof(OkObjectResult));
|
|
var okResult = result as OkObjectResult;
|
|
Assert.IsNotNull(okResult);
|
|
var returnedLevels = okResult.Value as IReadOnlyList<LevelDto>;
|
|
Assert.IsNotNull(returnedLevels);
|
|
Assert.AreEqual(2, returnedLevels.Count);
|
|
}
|
|
|
|
[TestMethod]
|
|
[TestCategory("LevelsController")]
|
|
[TestCategory("GetAllLevels")]
|
|
public async Task GetAllLevels_WithNoData_ReturnsEmptyList()
|
|
{
|
|
// Arrange
|
|
var expectedLevels = new List<LevelDto>();
|
|
|
|
_mockLevelService!.Setup(s => s.GetAllLevelsAsync(It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(expectedLevels);
|
|
|
|
// Act
|
|
var result = await _controller!.GetAllLevelsAsync();
|
|
|
|
// Assert
|
|
Assert.IsInstanceOfType(result, typeof(OkObjectResult));
|
|
var okResult = result as OkObjectResult;
|
|
Assert.IsNotNull(okResult);
|
|
var returnedLevels = okResult.Value as IReadOnlyList<LevelDto>;
|
|
Assert.IsNotNull(returnedLevels);
|
|
Assert.AreEqual(0, returnedLevels.Count);
|
|
}
|
|
|
|
// ==================== GET LEVEL BY ID TESTS ====================
|
|
|
|
[TestMethod]
|
|
[TestCategory("LevelsController")]
|
|
[TestCategory("GetLevelById")]
|
|
public async Task GetLevelById_WithExistingId_ReturnsOkWithLevel()
|
|
{
|
|
// Arrange
|
|
var expectedLevel = new LevelDto(1, "Beginner A1", "A1", 1);
|
|
|
|
_mockLevelService!.Setup(s => s.GetLevelByIdAsync(1, It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(expectedLevel);
|
|
|
|
// Act
|
|
var result = await _controller!.GetLevelByIdAsync(1);
|
|
|
|
// Assert
|
|
Assert.IsInstanceOfType(result, typeof(OkObjectResult));
|
|
var okResult = result as OkObjectResult;
|
|
Assert.IsNotNull(okResult);
|
|
var returnedLevel = okResult.Value as LevelDto;
|
|
Assert.IsNotNull(returnedLevel);
|
|
Assert.AreEqual(1, returnedLevel.Id);
|
|
Assert.AreEqual("Beginner A1", returnedLevel.Name);
|
|
}
|
|
|
|
[TestMethod]
|
|
[TestCategory("LevelsController")]
|
|
[TestCategory("GetLevelById")]
|
|
public async Task GetLevelById_WithNonExistingId_ReturnsNotFound()
|
|
{
|
|
// Arrange
|
|
_mockLevelService!.Setup(s => s.GetLevelByIdAsync(999, It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync((LevelDto?)null);
|
|
|
|
// Act
|
|
var result = await _controller!.GetLevelByIdAsync(999);
|
|
|
|
// Assert
|
|
Assert.IsInstanceOfType(result, typeof(NotFoundResult));
|
|
}
|
|
|
|
// ==================== GET LEVEL BY CODE TESTS ====================
|
|
|
|
[TestMethod]
|
|
[TestCategory("LevelsController")]
|
|
[TestCategory("GetLevelByCode")]
|
|
public async Task GetLevelByCode_WithExistingCode_ReturnsOkWithLevel()
|
|
{
|
|
// Arrange
|
|
var expectedLevel = new LevelDto(1, "Beginner A1", "A1", 1);
|
|
|
|
_mockLevelService!.Setup(s => s.GetLevelByCodeAsync("A1", It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(expectedLevel);
|
|
|
|
// Act
|
|
var result = await _controller!.GetLevelByCodeAsync("A1");
|
|
|
|
// Assert
|
|
Assert.IsInstanceOfType(result, typeof(OkObjectResult));
|
|
var okResult = result as OkObjectResult;
|
|
Assert.IsNotNull(okResult);
|
|
var returnedLevel = okResult.Value as LevelDto;
|
|
Assert.IsNotNull(returnedLevel);
|
|
Assert.AreEqual("A1", returnedLevel.Code);
|
|
}
|
|
|
|
[TestMethod]
|
|
[TestCategory("LevelsController")]
|
|
[TestCategory("GetLevelByCode")]
|
|
public async Task GetLevelByCode_WithNonExistingCode_ReturnsNotFound()
|
|
{
|
|
// Arrange
|
|
_mockLevelService!.Setup(s => s.GetLevelByCodeAsync("INVALID", It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync((LevelDto?)null);
|
|
|
|
// Act
|
|
var result = await _controller!.GetLevelByCodeAsync("INVALID");
|
|
|
|
// Assert
|
|
Assert.IsInstanceOfType(result, typeof(NotFoundResult));
|
|
}
|
|
|
|
// ==================== CREATE LEVEL TESTS ====================
|
|
|
|
[TestMethod]
|
|
[TestCategory("LevelsController")]
|
|
[TestCategory("CreateLevel")]
|
|
public async Task CreateLevel_WithValidData_ReturnsCreatedAtAction()
|
|
{
|
|
// Arrange
|
|
var createDto = new CreateLevelDto("Beginner A1", "A1", 1);
|
|
var expectedLevel = new LevelDto(1, "Beginner A1", "A1", 1);
|
|
|
|
_mockLevelService!.Setup(s => s.CreateLevelAsync(createDto, It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(expectedLevel);
|
|
|
|
// Act
|
|
var result = await _controller!.CreateLevelAsync(createDto);
|
|
|
|
// Assert
|
|
Assert.IsInstanceOfType(result, typeof(CreatedAtActionResult));
|
|
var createdResult = result as CreatedAtActionResult;
|
|
Assert.IsNotNull(createdResult);
|
|
var returnedLevel = createdResult.Value as LevelDto;
|
|
Assert.IsNotNull(returnedLevel);
|
|
Assert.AreEqual(1, returnedLevel.Id);
|
|
}
|
|
|
|
// ==================== UPDATE LEVEL TESTS ====================
|
|
|
|
[TestMethod]
|
|
[TestCategory("LevelsController")]
|
|
[TestCategory("UpdateLevel")]
|
|
public async Task UpdateLevel_WithExistingId_ReturnsOkWithUpdatedLevel()
|
|
{
|
|
// Arrange
|
|
var updateDto = new UpdateLevelDto("Updated A1", "A1", 1);
|
|
var expectedLevel = new LevelDto(1, "Updated A1", "A1", 1);
|
|
|
|
_mockLevelService!.Setup(s => s.UpdateLevelAsync(1, updateDto, It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(expectedLevel);
|
|
|
|
// Act
|
|
var result = await _controller!.UpdateLevelAsync(1, updateDto);
|
|
|
|
// Assert
|
|
Assert.IsInstanceOfType(result, typeof(OkObjectResult));
|
|
var okResult = result as OkObjectResult;
|
|
Assert.IsNotNull(okResult);
|
|
var returnedLevel = okResult.Value as LevelDto;
|
|
Assert.IsNotNull(returnedLevel);
|
|
Assert.AreEqual("Updated A1", returnedLevel.Name);
|
|
}
|
|
|
|
[TestMethod]
|
|
[TestCategory("LevelsController")]
|
|
[TestCategory("UpdateLevel")]
|
|
public async Task UpdateLevel_WithNonExistingId_ReturnsNotFound()
|
|
{
|
|
// Arrange
|
|
var updateDto = new UpdateLevelDto("Updated A1", "A1", 1);
|
|
|
|
_mockLevelService!.Setup(s => s.UpdateLevelAsync(999, updateDto, It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync((LevelDto?)null);
|
|
|
|
// Act
|
|
var result = await _controller!.UpdateLevelAsync(999, updateDto);
|
|
|
|
// Assert
|
|
Assert.IsInstanceOfType(result, typeof(NotFoundResult));
|
|
}
|
|
|
|
// ==================== DELETE LEVEL TESTS ====================
|
|
|
|
[TestMethod]
|
|
[TestCategory("LevelsController")]
|
|
[TestCategory("DeleteLevel")]
|
|
public async Task DeleteLevel_WithExistingId_ReturnsNoContent()
|
|
{
|
|
// Arrange
|
|
_mockLevelService!.Setup(s => s.DeleteLevelAsync(1, It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(true);
|
|
|
|
// Act
|
|
var result = await _controller!.DeleteLevelAsync(1);
|
|
|
|
// Assert
|
|
Assert.IsInstanceOfType(result, typeof(NoContentResult));
|
|
}
|
|
|
|
[TestMethod]
|
|
[TestCategory("LevelsController")]
|
|
[TestCategory("DeleteLevel")]
|
|
public async Task DeleteLevel_WithNonExistingId_ReturnsNotFound()
|
|
{
|
|
// Arrange
|
|
_mockLevelService!.Setup(s => s.DeleteLevelAsync(999, It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(false);
|
|
|
|
// Act
|
|
var result = await _controller!.DeleteLevelAsync(999);
|
|
|
|
// Assert
|
|
Assert.IsInstanceOfType(result, typeof(NotFoundResult));
|
|
}
|
|
|
|
// ==================== GET FIRST LEVEL TESTS ====================
|
|
|
|
[TestMethod]
|
|
[TestCategory("LevelsController")]
|
|
[TestCategory("GetFirstLevel")]
|
|
public async Task GetFirstLevel_WithData_ReturnsOkWithLevel()
|
|
{
|
|
// Arrange
|
|
var expectedLevel = new LevelDto(1, "Beginner A1", "A1", 1);
|
|
|
|
_mockLevelService!.Setup(s => s.GetFirstLevelAsync(It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(expectedLevel);
|
|
|
|
// Act
|
|
var result = await _controller!.GetFirstLevelAsync();
|
|
|
|
// Assert
|
|
Assert.IsInstanceOfType(result, typeof(OkObjectResult));
|
|
var okResult = result as OkObjectResult;
|
|
Assert.IsNotNull(okResult);
|
|
var returnedLevel = okResult.Value as LevelDto;
|
|
Assert.IsNotNull(returnedLevel);
|
|
Assert.AreEqual(1, returnedLevel.Order);
|
|
}
|
|
|
|
[TestMethod]
|
|
[TestCategory("LevelsController")]
|
|
[TestCategory("GetFirstLevel")]
|
|
public async Task GetFirstLevel_WithNoData_ReturnsNotFound()
|
|
{
|
|
// Arrange
|
|
_mockLevelService!.Setup(s => s.GetFirstLevelAsync(It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync((LevelDto?)null);
|
|
|
|
// Act
|
|
var result = await _controller!.GetFirstLevelAsync();
|
|
|
|
// Assert
|
|
Assert.IsInstanceOfType(result, typeof(NotFoundResult));
|
|
}
|
|
|
|
// ==================== GET NEXT LEVEL TESTS ====================
|
|
|
|
[TestMethod]
|
|
[TestCategory("LevelsController")]
|
|
[TestCategory("GetNextLevel")]
|
|
public async Task GetNextLevel_WithExistingCurrentLevel_ReturnsOkWithNextLevel()
|
|
{
|
|
// Arrange
|
|
var expectedLevel = new LevelDto(2, "Elementary A2", "A2", 2);
|
|
|
|
_mockLevelService!.Setup(s => s.GetNextLevelAsync(1, It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync(expectedLevel);
|
|
|
|
// Act
|
|
var result = await _controller!.GetNextLevelAsync(1);
|
|
|
|
// Assert
|
|
Assert.IsInstanceOfType(result, typeof(OkObjectResult));
|
|
var okResult = result as OkObjectResult;
|
|
Assert.IsNotNull(okResult);
|
|
var returnedLevel = okResult.Value as LevelDto;
|
|
Assert.IsNotNull(returnedLevel);
|
|
Assert.AreEqual(2, returnedLevel.Order);
|
|
}
|
|
|
|
[TestMethod]
|
|
[TestCategory("LevelsController")]
|
|
[TestCategory("GetNextLevel")]
|
|
public async Task GetNextLevel_WithNoNextLevel_ReturnsNotFound()
|
|
{
|
|
// Arrange
|
|
_mockLevelService!.Setup(s => s.GetNextLevelAsync(5, It.IsAny<CancellationToken>()))
|
|
.ReturnsAsync((LevelDto?)null);
|
|
|
|
// Act
|
|
var result = await _controller!.GetNextLevelAsync(5);
|
|
|
|
// Assert
|
|
Assert.IsInstanceOfType(result, typeof(NotFoundResult));
|
|
}
|
|
}
|