В чем разница между unit-тестированием и интеграционным тестированием?

«В чем разница между unit-тестированием и интеграционным тестированием?» — вопрос из категории Тестирование, который задают на 25% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Это разные уровни тестирования, решающие distinct задачи в процессе разработки.

Unit-тесты (Модульные тесты):

  • Цель: Проверить корректность работы отдельного, изолированного модуля (функции, метода, класса) в идеальных условиях.
  • Изоляция: Все внешние зависимости (база данных, файловая система, API) заменяются заглушками (mocks/stubs/fakes).
  • Скорость: Выполняются очень быстро (миллисекунды).
  • Пример (xUnit + Moq):

    public class OrderServiceTests {
    [Fact]
    public void CalculateTotal_WithItems_ReturnsCorrectSum() {
        // Arrange
        var mockItem = new Mock<IOrderItem>();
        mockItem.Setup(i => i.Price).Returns(100);
        var service = new OrderService();
    
        // Act
        var total = service.CalculateTotal(new List<IOrderItem> { mockItem.Object, mockItem.Object });
    
        // Assert
        Assert.Equal(200, total);
    }
    }

Интеграционные тесты:

  • Цель: Проверить взаимодействие нескольких компонентов или системы с внешними ресурсами (БД, файлы, микросервисы).
  • Изоляция: Минимальная или отсутствует. Тесты работают с реальными или приближенными к реальным зависимостями (например, тестовой БД).
  • Скорость: Выполняются медленно (секунды или минуты).
  • Пример (интеграция с БД):

    public class UserRepositoryIntegrationTests : IClassFixture<DatabaseFixture> {
    private readonly AppDbContext _dbContext;
    
    public UserRepositoryIntegrationTests(DatabaseFixture fixture) {
        _dbContext = fixture.CreateContext(); // Поднимается тестовая БД
    }
    
    [Fact]
    public async Task CreateUser_ValidData_UserSavedInDatabase() {
        // Arrange
        var repo = new UserRepository(_dbContext);
        var user = new User { Name = "Test" };
    
        // Act
        await repo.AddAsync(user);
        await _dbContext.SaveChangesAsync();
    
        // Assert
        var userFromDb = await _dbContext.Users.FindAsync(user.Id);
        Assert.NotNull(userFromDb);
        Assert.Equal("Test", userFromDb.Name);
    }
    }

Итог: Unit-тесты — это быстрые, изолированные «кирпичики» проверки логики. Интеграционные тесты — это более медленные, комплексные проверки того, что эти «кирпичики» правильно склеиваются между собой и с внешним миром.