🧪 测试

微服务测试策略:从单元测试到集成测试

全面介绍微服务架构中的测试策略,包括单元测试、集成测试、契约测试、端到端测试等多种测试方法

一、微服务测试挑战

微服务架构的分布式特性给测试带来了新的挑战,需要多层次、多角度的测试策略。

二、单元测试最佳实践

单元测试验证单个组件的功能,使用Mock隔离外部依赖。

[TestClass]
public class ProductServiceTests
{
    private Mock<IProductRepository> _mockRepo;
    private ProductService _service;

    [TestInitialize]
    public void Setup()
    {
        _mockRepo = new Mock<IProductRepository>();
        _service = new ProductService(_mockRepo.Object);
    }

    [TestMethod]
    public async Task GetProduct_ReturnsProduct_WhenExists()
    {
        // Arrange
        var expectedProduct = new Product { Id = 1, Name = "Test" };
        _mockRepo.Setup(r => r.GetByIdAsync(1))
                 .ReturnsAsync(expectedProduct);

        // Act
        var result = await _service.GetProductAsync(1);

        // Assert
        Assert.AreEqual(expectedProduct.Id, result.Id);
        _mockRepo.Verify(r => r.GetByIdAsync(1), Times.Once);
    }
}

三、集成测试策略

集成测试验证多个组件之间的交互。

public class ProductControllerIntegrationTests
{
    private HttpClient _client;
    private TestServer _server;

    [SetUp]
    public void Setup()
    {
        _server = new TestServer(new WebHostBuilder()
            .UseStartup<Startup>()
            .ConfigureTestServices(services => {
                // 替换测试依赖
                services.AddScoped<IDbContext, TestDbContext>();
            }));
        _client = _server.CreateClient();
    }

    [Test]
    public async Task GetProducts_ReturnsOk()
    {
        var response = await _client.GetAsync("/api/products");
        response.EnsureSuccessStatusCode();
        var content = await response.Content.ReadAsStringAsync();
        Assert.IsNotNull(content);
    }
}

四、契约测试

契约测试验证服务之间的API契约一致性。

// 使用 PactNet 进行契约测试
public class ProductApiConsumerTests
{
    [Test]
    public void GetProduct_ShouldReturnProduct()
    {
        using var pact = new PactBuilder(new PactConfig())
            .ServiceConsumer("Consumer")
            .HasPactWith("ProductService");

        pact.UponReceiving("a request for product")
            .Given("product 1 exists")
            .WithRequest(HttpMethod.Get, "/api/products/1")
            .WillRespondWith(HttpStatusCode.OK,
                headers: new Dictionary<string, string> {
                    { "Content-Type", "application/json" }
                },
                body: new {
                    id = 1,
                    name = "Test Product"
                });

        pact.Verify(() => {
            var client = new ProductApiClient("http://localhost:9292");
            var product = client.GetProduct(1);
            Assert.AreEqual(1, product.Id);
        });
    }
}

五、端到端测试

端到端测试验证完整的业务流程。

六、组件测试

组件测试验证单个服务的完整功能。

七、性能测试

使用k6等工具进行性能和压力测试。

// k6 性能测试脚本
import http from 'k6/http';
import { sleep, check } from 'k6';

export const options = {
    vus: 100,
    duration: '30s',
};

export default function () {
    const res = http.get('https://api.example.com/products');
    check(res, {
        'status was 200': (r) => r.status == 200,
        'response time < 200ms': (r) => r.timings.duration < 200,
    });
    sleep(1);
}

八、测试数据管理

管理测试数据确保测试的可重复性。

九、测试覆盖率

使用Coverlet等工具衡量测试覆盖率。

十、测试策略总结

根据测试金字塔合理分配测试资源,注重测试的有效性和效率。