Ответ
Я преимущественно работаю с xUnit как с наиболее гибким и современным фреймворком для .NET. Вот ключевые атрибуты и их применение:
Основные атрибуты xUnit:
[Fact]– помечает метод как тестовый, который должен выполняться без внешних данных.[Fact] public void CalculateTotal_EmptyCart_ReturnsZero() { var cart = new ShoppingCart(); var total = cart.CalculateTotal(); Assert.Equal(0, total); }[Theory]– помечает параметризованный тест. Данные для него предоставляются отдельными атрибутами.[InlineData]– самый простой способ передать данные в[Theory]. Данные задаются прямо в атрибуте.[Theory] [InlineData(5, 3, 8)] // a, b, expected [InlineData(-1, 1, 0)] [InlineData(0, 0, 0)] public void Add_TwoNumbers_ReturnsSum(int a, int b, int expected) { var calculator = new Calculator(); var result = calculator.Add(a, b); Assert.Equal(expected, result); }-
[MemberData]– позволяет использовать статическое свойство или метод класса для предоставления сложных наборов тестовых данных (например, объекты).public static IEnumerable<object[]> TestData => new List<object[]> { new object[] { new User("Alice", 30), true }, new object[] { new User("Bob", 17), false } }; [Theory] [MemberData(nameof(TestData))] public void User_IsAdult_ReturnsCorrectValue(User user, bool expectedIsAdult) { var result = user.IsAdult(); Assert.Equal(expectedIsAdult, result); } [ClassData]– похож на[MemberData], но данные предоставляет отдельный класс, реализующийIEnumerable<object[]>. Удобно для организации больших наборов данных.
Атрибуты для управления выполнением:
[Trait("Category", "Integration")]– для категоризации тестов (например, чтобы запускать только "Unit" или только "Integration" тесты в пайплайне).[Fact(Skip = "Требуется доработка моков")]– временно отключает тест.
Сравнение с другими фреймворками:
- NUnit:
[Test](аналог[Fact]),[TestCase](аналог[InlineData]). - MSTest:
[TestMethod],[DataTestMethod],[DataRow].
Практический совет: Используйте [Theory] с [MemberData] или [ClassData] для тестирования пограничных случаев (boundary values) и различных сценариев, чтобы избежать дублирования кода тестов.
Ответ 18+ 🔞
Слушай, а вот xUnit — это вообще огонь, если ты на .NET работаешь. Гибкий, современный, без лишнего олдскульного говна. Я на нём собаку съел, так что давай разжёвываю, как есть.
Основные штуки, без которых нихуя не работает:
-
[Fact]— это типа базовый тест, который сам по себе, без всяких подачек данных. Написал логику, проверил — всё.[Fact] public void CalculateTotal_EmptyCart_ReturnsZero() { var cart = new ShoppingCart(); var total = cart.CalculateTotal(); Assert.Equal(0, total); }Вот, видишь? Корзина пустая — итог ноль. Никаких подвохов.
-
[Theory]— а вот это уже интереснее. Это когда один тест, но ты его прогоняешь на разных данных. Как будто один сценарий, но с разными вводными. Без него — копипаста до скончания времён. -
[InlineData]— самый простой способ накормить[Theory]. Данные прямо в атрибут пихаешь, и поехали.[Theory] [InlineData(5, 3, 8)] // a, b, expected [InlineData(-1, 1, 0)] [InlineData(0, 0, 0)] public void Add_TwoNumbers_ReturnsSum(int a, int b, int expected) { var calculator = new Calculator(); var result = calculator.Add(a, b); Assert.Equal(expected, result); }Смотри, один метод, а проверяет три случая сразу. Красота же, ёпта!
-
[MemberData]— а это когда[InlineData]уже не лезет, потому что данные сложные. Тут ты тащишь их из отдельного свойства или метода в том же классе. Идеально для объектов.public static IEnumerable<object[]> TestData => new List<object[]> { new object[] { new User("Alice", 30), true }, new object[] { new User("Bob", 17), false } }; [Theory] [MemberData(nameof(TestData))] public void User_IsAdult_ReturnsCorrectValue(User user, bool expectedIsAdult) { var result = user.IsAdult(); Assert.Equal(expectedIsAdult, result); }Видал? Целые объекты
Userв тест засунул. Мощь! -
[ClassData]— ну а это уже для совсем распиздяйских больших наборов данных. Выносишь всё в отдельный класс, чтобы в основном тесте не засирать глаза.
Атрибуты, чтобы управлять этим цирком:
[Trait("Category", "Integration")]— вешаешь бирку на тест. Типа «интеграционный», «медленный», «пиздец какой важный». Потом в пайплайне можешь только быстрые unit-тесты гонять, а эти — отдельно.[Fact(Skip = "Требуется доработка моков")]— классика жанра. Тест сломался, а фиксить сейчас влом? Щёлк — и он пропускается. Главное потом не забыть, а то так и будут висеть, эти «временно отключённые», пока все не похудеют.
Если вдруг вспомнил про старьё:
- NUnit: там
[Test]— это как наш[Fact], а[TestCase]— аналог[InlineData]. В целом, тоже ничего, но xUnit как-то поприятнее. - MSTest:
[TestMethod],[DataTestMethod],[DataRow]. Ну, сойдёт, если ты любитель микроскопом гвозди забивать.
Совет от бывалого, чтобы не выстрелить себе в ногу: Не городи кучу одинаковых [Fact] с разными цифрами. Бери [Theory] и корми его через [MemberData] или [ClassData] всеми пограничными случаями — нулями, отрицательными числами, null'ами, херовыми строками. Так и покрытие лучше, и сам не сойдёшь с ума от однообразия.