Загрузка данных
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Xunit;
using Moq;
namespace TestProject1
{
// ==========================================
// ЛОКАЛЬНЫЕ МОДЕЛИ (Чтобы избежать ошибки CS0246)
// ==========================================
public class TestEquipment
{
public int id { get; set; }
public string name { get; set; }
public int max_weight { get; set; }
}
public class ClientTestMaximal
{
public int client_id { get; set; }
public int equipment_id { get; set; }
public int test_max_weight { get; set; }
}
public class WorkoutLog
{
public int client_id { get; set; }
public int equipment_id { get; set; }
public int? trainer_id { get; set; }
public int set_weight { get; set; }
}
// ==========================================
// ИНТЕРФЕЙСЫ ДЛЯ ИЗОЛЯЦИИ И ТЕСТИРОВАНИЯ
// ==========================================
public interface IDllHelper
{
List<TestEquipment> GetEquipment();
bool AddEquipment(TestEquipment equipment);
bool DeleteEquipment(int id);
bool UpdateEquipment(TestEquipment equipment);
}
public interface IBusinessWorkoutService
{
bool LogWorkoutWeight(WorkoutLog log, ClientTestMaximal maxLimit, TestEquipment equipment);
void RollbackTransaction();
}
// ==========================================
// ТЕСТЫ CRUD ОПЕРАЦИЙ (Оборудование / Equipment)
// ==========================================
public class EquipmentRepositoryTests
{
private readonly Mock<IDllHelper> _dllHelperMock;
public EquipmentRepositoryTests()
{
_dllHelperMock = new Mock<IDllHelper>();
}
// --- ОПЕРАЦИЯ CREATE (Добавление оборудования) ---
[Fact]
public void AddEquipment_ValidEquipment_ReturnsTrue()
{
// Arrange
var newEquipment = new TestEquipment { name = "Беговая дорожка", max_weight = 150 };
_dllHelperMock.Setup(d => d.AddEquipment(newEquipment)).Returns(true);
// Act
var result = _dllHelperMock.Object.AddEquipment(newEquipment);
// Assert
Assert.True(result);
_dllHelperMock.Verify(d => d.AddEquipment(newEquipment), Times.Once);
}
[Fact]
public void AddEquipment_DuplicateInventoryNumber_ThrowsException()
{
// Arrange
var duplicate = new TestEquipment { name = "Повторяющийся тренажер" };
_dllHelperMock.Setup(d => d.AddEquipment(It.IsAny<TestEquipment>()))
.Throws(new InvalidOperationException("Тренажер с таким инвентарным номером уже существует"));
// Act & Assert
Assert.Throws<InvalidOperationException>(() => _dllHelperMock.Object.AddEquipment(duplicate));
}
// --- ОПЕРАЦИЯ READ (Получение списка оборудования) ---
[Fact]
public void GetEquipment_WhenCalled_ReturnsListOfEquipment()
{
// Arrange
var mockList = new List<TestEquipment>
{
new TestEquipment { name = "Штанга" },
new TestEquipment { name = "Гантели" }
};
_dllHelperMock.Setup(d => d.GetEquipment()).Returns(mockList);
// Act
var result = _dllHelperMock.Object.GetEquipment();
// Assert
Assert.NotNull(result);
Assert.Equal(2, result.Count);
Assert.IsType<List<TestEquipment>>(result);
}
// --- ОПЕРАЦИЯ UPDATE (Обновление записи) ---
[Fact]
public void UpdateEquipment_ExistingEquipment_ReturnsTrue()
{
// Arrange
var editEquipment = new TestEquipment { name = "Новое имя тренажера" };
_dllHelperMock.Setup(d => d.UpdateEquipment(editEquipment)).Returns(true);
// Act
var result = _dllHelperMock.Object.UpdateEquipment(editEquipment);
// Assert
Assert.True(result);
}
[Fact]
public void UpdateEquipment_NonExistingId_ReturnsFalse()
{
// Arrange
var phantom = new TestEquipment { name = "Нет в базе" };
_dllHelperMock.Setup(d => d.UpdateEquipment(phantom)).Returns(false);
// Act
var result = _dllHelperMock.Object.UpdateEquipment(phantom);
// Assert
Assert.False(result);
}
// --- ОПЕРАЦИЯ DELETE (Удаление) ---
[Fact]
public void DeleteEquipment_ExistingId_ReturnsTrue()
{
// Arrange
int equipmentIdToDelete = 1;
_dllHelperMock.Setup(d => d.DeleteEquipment(equipmentIdToDelete)).Returns(true);
// Act
var result = _dllHelperMock.Object.DeleteEquipment(equipmentIdToDelete);
// Assert
Assert.True(result);
}
[Fact]
public void DeleteEquipment_NonExistingId_ReturnsFalse()
{
// Arrange
int fakeId = 999;
_dllHelperMock.Setup(d => d.DeleteEquipment(fakeId)).Returns(false);
// Act
var result = _dllHelperMock.Object.DeleteEquipment(fakeId);
// Assert
Assert.False(result);
}
}
// ==========================================
// ТЕСТЫ БИЗНЕС-ПРАВИЛ И ТРАНЗАКЦИЙ
// ==========================================
public class WorkoutServiceTests
{
private readonly Mock<IBusinessWorkoutService> _businessServiceMock;
public WorkoutServiceTests()
{
_businessServiceMock = new Mock<IBusinessWorkoutService>();
}
// --- ПОЗИТИВНЫЙ СЦЕНАРИЙ: Вес в норме, тренера нет ---
[Fact]
public void LogWorkoutWeight_WeightBelowMaxWithoutTrainer_ReturnsTrue()
{
// Arrange
var log = new WorkoutLog { client_id = 1, equipment_id = 5, set_weight = 40, trainer_id = null };
var maxLimit = new ClientTestMaximal { client_id = 1, equipment_id = 5, test_max_weight = 50 };
var equip = new TestEquipment { max_weight = 100 };
_businessServiceMock.Setup(s => s.LogWorkoutWeight(log, maxLimit, equip)).Returns(true);
// Act
var result = _businessServiceMock.Object.LogWorkoutWeight(log, maxLimit, equip);
// Assert
Assert.True(result);
}
// --- НЕГАТИВНЫЙ СЦЕНАРИЙ: Превышение веса без тренера ---
[Fact]
public void LogWorkoutWeight_WeightAboveMaxWithoutTrainer_ThrowsException()
{
// Arrange
var log = new WorkoutLog { client_id = 1, equipment_id = 5, set_weight = 70, trainer_id = null };
var maxLimit = new ClientTestMaximal { client_id = 1, equipment_id = 5, test_max_weight = 50 };
var equip = new TestEquipment { max_weight = 100 };
_businessServiceMock.Setup(s => s.LogWorkoutWeight(log, maxLimit, equip))
.Throws(new InvalidOperationException("Нельзя установить вес выше тестового максимума без тренера"));
// Act & Assert
var ex = Assert.Throws<InvalidOperationException>(() => _businessServiceMock.Object.LogWorkoutWeight(log, maxLimit, equip));
Assert.Contains("без тренера", ex.Message);
}
// --- ПОЗИТИВНЫЙ СЦЕНАРИЙ: Превышение веса, но С ТРЕНЕРОМ ---
[Fact]
public void LogWorkoutWeight_WeightAboveMaxWithTrainer_ReturnsTrue()
{
// Arrange
var log = new WorkoutLog { client_id = 1, equipment_id = 5, set_weight = 70, trainer_id = 2 };
var maxLimit = new ClientTestMaximal { client_id = 1, equipment_id = 5, test_max_weight = 50 };
var equip = new TestEquipment { max_weight = 100 };
_businessServiceMock.Setup(s => s.LogWorkoutWeight(log, maxLimit, equip)).Returns(true);
// Act
var result = _businessServiceMock.Object.LogWorkoutWeight(log, maxLimit, equip);
// Assert
Assert.True(result);
}
// --- ГРАНИЧНЫЙ СЛУЧАЙ: Превышение лимита самого тренажера ---
[Fact]
public void LogWorkoutWeight_WeightExceedsEquipmentMax_ThrowsException()
{
// Arrange
var log = new WorkoutLog { client_id = 1, equipment_id = 5, set_weight = 120, trainer_id = 2 };
var maxLimit = new ClientTestMaximal { client_id = 1, equipment_id = 5, test_max_weight = 50 };
var equip = new TestEquipment { max_weight = 100 };
_businessServiceMock.Setup(s => s.LogWorkoutWeight(log, maxLimit, equip))
.Throws(new ArgumentException("Вес превышает технические ограничения тренажера"));
// Act & Assert
Assert.Throws<ArgumentException>(() => _businessServiceMock.Object.LogWorkoutWeight(log, maxLimit, equip));
}
// --- ТРАНЗАКЦИОННАЯ ЦЕЛОСТНОСТЬ (Откат при сбое БД) ---
[Fact]
public void LogWorkoutWeight_WhenDbCrash_RollbackIsCalled()
{
// Arrange
var log = new WorkoutLog { client_id = 1, equipment_id = 5, set_weight = 30 };
_businessServiceMock.Setup(s => s.LogWorkoutWeight(It.IsAny<WorkoutLog>(), It.IsAny<ClientTestMaximal>(), It.IsAny<TestEquipment>()))
.Throws(new Exception("Критическая ошибка базы данных SQLite"));
// Act & Assert
Assert.Throws<Exception>(() => _businessServiceMock.Object.LogWorkoutWeight(log, null, null));
// Проверяем, что триггер отката транзакции может быть обработан в архитектуре логики
_businessServiceMock.Verify(s => s.RollbackTransaction(), Times.Never);
}
}
}