Test-Driven Development (TDD) là một development methodology trong đó tests được viết trước khi viết code. Chu trình cơ bản là: Red - Green - Refactor.
// Step 1: Write failing test (Red)
// CalculatorTests.cs
public class CalculatorTests
{
[Fact]
public void Add_TwoNumbers_ReturnsSum()
{
// Arrange
var calculator = new Calculator();
// Act
var result = calculator.Add(2, 3);
// Assert
Assert.Equal(5, result);
}
}
// Step 2: Write minimal code (Green)
// Calculator.cs
public class Calculator
{
public int Add(int a, int b)
{
return 5; // Minimal implementation to pass
}
}
// Step 3: Refactor - implement properly
public class Calculator
{
public int Add(int a, int b)
{
return a + b;
}
}
// StringCalculator.cs
public class StringCalculator
{
public int Add(string numbers)
{
if (string.IsNullOrEmpty(numbers))
return 0;
var parts = numbers.Split(',');
return parts.Sum(int.Parse);
}
}
// StringCalculatorTests.cs
public class StringCalculatorTests
{
[Fact]
public void Add_EmptyString_ReturnsZero()
{
var calculator = new StringCalculator();
var result = calculator.Add("");
Assert.Equal(0, result);
}
[Fact]
public void Add_SingleNumber_ReturnsThatNumber()
{
var result = new StringCalculator().Add("5");
Assert.Equal(5, result);
}
[Fact]
public void Add_TwoNumbers_ReturnsSum()
{
var result = new StringCalculator().Add("1,2");
Assert.Equal(3, result);
}
[Fact]
public void Add_UnknownAmountOfNumbers_ReturnsSum()
{
var result = new StringCalculator().Add("1,2,3,4,5");
Assert.Equal(15, result);
}
}
// Service using interface for dependency
public interface IOrderRepository
{
Task<Order> GetByIdAsync(Guid id);
}
public class OrderService
{
private readonly IOrderRepository _repository;
public OrderService(IOrderRepository repository)
{
_repository = repository;
}
public async Task<bool> ValidateOrderAsync(Guid orderId)
{
var order = await _repository.GetByIdAsync(orderId);
if (order == null)
return false;
return order.Status == OrderStatus.Active;
}
}
// Testing with mocking
public class OrderServiceTests
{
[Fact]
public async Task ValidateOrderAsync_ActiveOrder_ReturnsTrue()
{
// Arrange
var mockRepo = new Mock<IOrderRepository>();
var order = new Order { Id = Guid.NewGuid(), Status = OrderStatus.Active };
mockRepo.Setup(r => r.GetByIdAsync(order.Id))
.ReturnsAsync(order);
var service = new OrderService(mockRepo.Object);
// Act
var result = await service.ValidateOrderAsync(order.Id);
// Assert
Assert.True(result);
}
[Fact]
public async Task ValidateOrderAsync_OrderNotFound_ReturnsFalse()
{
var mockRepo = new Mock<IOrderRepository>();
mockRepo.Setup(r => r.GetByIdAsync(It.IsAny<Guid>()))
.ReturnsAsync((Order)null);
var service = new OrderService(mockRepo.Object);
var result = await service.ValidateOrderAsync(Guid.NewGuid());
Assert.False(result);
}
}
public class OrderTests
{
[Fact]
public void PlaceOrder_EmptyItems_ThrowsException()
{
var order = new Order();
Assert.Throws<InvalidOperationException>(() => order.Place());
}
[Fact]
public void PlaceOrder_AlreadyPlaced_ThrowsException()
{
var order = new Order();
order.AddItem(CreateSampleProduct(), 1);
order.Place();
Assert.Throws<InvalidOperationException>(() => order.Place());
}
[Fact]
public void AddItem_NegativeQuantity_ThrowsException()
{
var order = new Order();
Assert.Throws<ArgumentException>(() =>
order.AddItem(CreateSampleProduct(), -1));
}
private Product CreateSampleProduct()
{
return new Product("Test Product", 10.00m);
}
}
[Fact]
public void Example()
{
// Arrange - Setup objects, prepare data
var calculator = new Calculator();
var expected = 10;
// Act - Execute the functionality
var result = calculator.Add(6, 4);
// Assert - Verify the result
Assert.Equal(expected, result);
}
public class OrderServiceTests
{
// Order Creation Tests
[Fact] public void CreateOrder_ValidData_ReturnsOrder() { }
[Fact] public void CreateOrder_NullData_ThrowsException() { }
// Order Modification Tests
[Fact] public void AddItem_ValidItem_AddsToOrder() { }
[Fact] public void RemoveItem_ExistingItem_RemovesFromOrder() { }
// Order Processing Tests
[Fact] public void Place_PlacedOrder_ChangesStatus() { }
[Fact] public void Cancel_CancellableOrder_ChangesStatus() { }
}