Blog
Oct 8, 2025 - 11 MIN READ
Testing Backend Services: Unit, Integration, and Contract Testing

Testing Backend Services: Unit, Integration, and Contract Testing

Comprehensive guide to testing strategies for backend applications including unit testing patterns, integration testing with real dependencies, and API contract testing.

Your Name

Your Name

Testing is where I've learned the most humbling lessons as a developer. Systems I was confident about collapsed in production because I hadn't tested the right scenarios.

Understanding the Testing Pyramid

Not all tests are equally valuable. I've evolved my approach based on which tests actually catch real bugs.

      /\
     /E2E\
    /     \
   /-------\
  / Integration\
 /             \
/-----------\
/   Unit Tests \
/               \
/-----------------\
  • Unit Tests (70%): Fast, focused, numerous
  • Integration Tests (20%): Slower, test interactions
  • E2E/Contract Tests (10%): Slowest, test complete flows

Phase 1: Solid Unit Testing

Unit tests form the foundation. They should be fast, focused, and numerous.

Structuring Testable Code

// BAD - Tightly coupled
public class OrderService
{
    private readonly SqlConnection _connection;
    
    public OrderService()
    {
        _connection = new SqlConnection("connectionstring");
    }
}

// GOOD - Depends on abstractions
public class OrderService
{
    private readonly IOrderRepository _repository;
    
    public OrderService(IOrderRepository repository)
    {
        _repository = repository;
    }
}

Comprehensive Unit Tests

public class OrderServiceTests
{
    private readonly Mock<IOrderRepository> _repositoryMock;
    private readonly OrderService _service;
    
    [Fact]
    public async Task PlaceOrder_WithValidOrder_SavesOrder()
    {
        var order = new Order { Id = 1, Amount = 100m };
        
        await _service.PlaceOrderAsync(order);
        
        _repositoryMock.Verify(
            r => r.SaveAsync(It.IsAny<Order>()),
            Times.Once);
    }
}

Phase 2: Integration Testing

Integration tests verify that components work together.

Testing with Real Dependencies

public class IntegrationTestFixture : IAsyncLifetime
{
    public ApplicationDbContext DbContext { get; private set; }
    
    public async Task InitializeAsync()
    {
        var services = new ServiceCollection();
        
        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(
                "Server=localhost,1433;Database=TestDb;User Id=sa;Password=YourPassword123!;Encrypt=false;"));
        
        var serviceProvider = services.BuildServiceProvider();
        DbContext = serviceProvider.GetRequiredService<ApplicationDbContext>();
        
        await DbContext.Database.MigrateAsync();
    }
    
    public async Task DisposeAsync()
    {
        DbContext?.Dispose();
    }
}

Phase 3: Contract Testing

Contract tests verify that services communicate correctly.

Conclusion

Testing is not about coverage percentage—it's about confidence. The tests that have saved me most are integration tests catching interaction bugs.

Built with Nuxt UI • © 2025 Behnam Nouri