Продолжаем тему с юнит тестами, и поговорим какие существуют антипаттерны при написании юнит тестов.
🔎Тестирование приватных методов
У вас есть класс
PaymentProcessor, который обрабатывает платежи и содержит приватный метод для валидации транзакций.class PaymentProcessor {
private validateTransaction(transaction: Transaction): boolean {
// сложная логика
return transaction.amount > 0 && transaction.currency === 'USD';
}
processPayment(transaction: Transaction): string {
if (this.validateTransaction(transaction)) {
return 'Payment processed';
} else {
return 'Invalid transaction';
}
}
}Антипаттерн:
Делаем метод публичным и тестирование метода
validateTransaction напрямую.Почему это плохо:
✖Нарушает принцип инкапсуляции.
✖Тесты становятся хрупкими при изменении внутренней реализации.
✅Решение:
Тестировать публичный метод
processPayment, который использует приватный метод.Или провести рефакторинг и вынести
validateTransaction в отдельный класс.🔎Раскрытие приватного состояния объекта
Класс
Inventory управляет списком товаров на складе.class Inventory {
private items: Item[] = [];
addItem(item: Item): void {
this.items.push(item);
}
getItems(): ReadonlyArray<Item> {
return this.items;
}
// Другие методы...
}Антипаттерн:
Чтобы упростить тестирование, приватное свойство
items делается публичным.✅Решение:
Тестировать публичный метод
processPayment, который использует приватный метод.🔎Утечка доменных знаний в тесты
Система рассчитывает налог в зависимости от категории продукта.
class TaxCalculator {
calculateTax(product: Product): number {
if (product.category === 'Food') {
return product.price * 0.05;
} else if (product.category === 'Electronics') {
return product.price * 0.2;
}
return product.price * 0.1;
}
}Антипаттерн:
Тест дублирует бизнес-логику при расчете ожидаемого результата.
describe('TaxCalculator', () => {
it('should calculate tax for food category', () => {
const calculator = new TaxCalculator();
const product = { price: 100, category: 'Food' };
// тут дублируется логика
const expectedTax = product.price * 0.05;
const tax = calculator.calculateTax(product);
expect(tax).toBe(expectedTax);
});
});Почему это плохо:
✖Тест повторяет логику, которую должен проверять.
✖При изменении логики необходимо менять и код теста.
✅Решение:
Использовать конкретные значения для ожидаемых результатов.
describe('TaxCalculator', () => {
it('should calculate 5% tax for food category', () => {
const calculator = new TaxCalculator();
const product = { price: 100, category: 'Food' };
const tax = calculator.calculateTax(product);
expect(tax).toBe(5);
});
it('should calculate 20% tax for electronics category', () => {
const calculator = new TaxCalculator();
const product = { price: 200, category: 'Electronics' };
const tax = calculator.calculateTax(product);
expect(tax).toBe(40);
});
}); Теги: #unitTests #cleanСode #TDD #BDD #learning #recommendation #practices