Ответ
Да, активно пишу модульные, интеграционные и end-to-end тесты в экосистеме .NET. В работе использую следующий стек и подходы:
Стек технологий:
- Фреймворки: xUnit (предпочтительно), NUnit, MSTest
- Mocking: Moq, NSubstitute
- Assertions: FluentAssertions для читаемых проверок
- Интеграционное тестирование: Testcontainers для поднятия реальных БД в Docker, WebApplicationFactory для ASP.NET Core
Пример модульного теста с xUnit и Moq:
public class OrderServiceTests
{
private readonly Mock<IRepository<Order>> _mockRepo;
private readonly OrderService _sut; // System Under Test
public OrderServiceTests()
{
_mockRepo = new Mock<IRepository<Order>>();
_sut = new OrderService(_mockRepo.Object);
}
[Fact]
public async Task ProcessOrder_ValidOrder_CallsRepositoryAndReturnsId()
{
// Arrange
var order = new Order { Id = 0, Total = 100 };
_mockRepo.Setup(r => r.AddAsync(It.IsAny<Order>()))
.Callback<Order>(o => o.Id = 123) // Симулируем присвоение ID
.Returns(Task.CompletedTask);
// Act
var resultId = await _sut.ProcessOrderAsync(order);
// Assert
resultId.Should().Be(123); // FluentAssertions
_mockRepo.Verify(r => r.AddAsync(order), Times.Once);
_mockRepo.VerifyNoOtherCalls();
}
[Theory]
[InlineData(0)]
[InlineData(-10)]
public void ValidateOrder_InvalidTotal_ThrowsException(decimal invalidTotal)
{
var order = new Order { Total = invalidTotal };
Assert.Throws<ArgumentException>(() => _sut.ValidateOrder(order));
}
}
Ключевые практики:
- Изоляция: Тесты не зависят от внешних сервисов (используются моки) и друг от друга.
- Паттерн AAA: Чёткое разделение на Arrange (подготовка), Act (действие), Assert (проверка).
- Смысловые имена: Имена тестовых методов следуют шаблону
MethodName_StateUnderTest_ExpectedBehavior. - CI/CD интеграция: Тесты запускаются автоматически в пайплайнах (GitHub Actions, Azure DevOps).
- Покрытие критических путей: Фокус на тестировании бизнес-логики, edge-кейсов и обработки ошибок, а не на достижении формального процента покрытия.