Ответ
Это разные уровни тестирования, решающие 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-тесты — это быстрые, изолированные «кирпичики» проверки логики. Интеграционные тесты — это более медленные, комплексные проверки того, что эти «кирпичики» правильно склеиваются между собой и с внешним миром.
Ответ 18+ 🔞
А, ну это же классика, про которую все говорят, но половина нихуя не понимает разницы! Смотри, тут всё просто, как три копейки, если не усложнять.
Юнит-тесты (или модульные, кому как удобнее) Их задача — проверить одну мелкую детальку в идеальных условиях. Представь, что у тебя есть функция, которая складывает два числа. Ты её вырываешь из всего контекста, сажаешь в стерильную комнату и начинаешь тыкать: «А ну-ка, сложи 2 и 2!». Все её друзья — база данных, файловая система, соседний микросервис — остаются за дверью в виде заглушек. Эти тесты быстрые, как угорелые, потому что по сути гоняют голую логику.
Вот, смотри на пример, тут всё понятно:
public class OrderServiceTests {
[Fact]
public void CalculateTotal_WithItems_ReturnsCorrectSum() {
// Arrange (Готовимся)
var mockItem = new Mock<IOrderItem>(); // Это не реальный товар, а муляж!
mockItem.Setup(i => i.Price).Returns(100); // Говорим муляжу: «Твоя цена — 100».
var service = new OrderService();
// Act (Действуем)
var total = service.CalculateTotal(new List<IOrderItem> { mockItem.Object, mockItem.Object }); // Скидываем два муляжа
// Assert (Проверяем)
Assert.Equal(200, total); // Ждём, что сервис не обосрётся и вернёт 200.
}
}
Суть в том, что если тест упадёт, ты сразу знаешь — косяк в логике CalculateTotal. Не в БД, не в сети, а прямо вот тут, в этих трёх строчках. Удобно, чё.
Интеграционные тесты А вот это уже поинтереснее. Тут мы проверяем, как наши детальки на самом деле работают вместе. Всё по-взрослому: поднимается тестовая база, наливается тестовое вино, и компоненты начинают общаться как в реальной жизни, а не через муляжи.
Они медленные, потому что базу поднять — это не хухры-мухры, и если что-то пошло не так, то понять, где именно — уже сложнее. Упасть может из-за неправильного SQL, из-за кривых настроек подключения, да хуй его знает из-за чего ещё.
Глянь, как это выглядит:
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); // Если null — всё, пиши пропало, запись не сохранилась
Assert.Equal("Test", userFromDb.Name); // А если сохранилась, то с правильным именем ли?
}
}
Короче, резюмирую:
- Юнит-тесты — это когда ты проверяешь мотор на стенде, в идеальной чистоте. Быстро и точно.
- Интеграционные тесты — это когда ты этот мотор уже в машину поставил и пытаешься завести. Медленнее, но зато видно, как он с коробкой передач и бензобаком дружит.
И да, если юнит-тест падает — это обычно твоя локальная ошибка, которую быстро починишь. А если интеграционный влетел в тартарары — готовься к весёлому расследованию, потому что причин может быть овердохуища. Вот и вся магия, без всяких там ебушки-воробушки.
Видео-ответы
▶
▶
▶
▶
▶