You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何对基于SelectPdf的GetPdf方法进行单元测试?

如何对基于SelectPdf的GetPdf方法进行单元测试?

嘿,我来给你捋捋怎么搞定这个单元测试的问题。首先先看看你原来的方法代码:

public PdfDocument GetPdf(string requestUrl) {
    var converter = new HtmlToPdf();
    var response = converter.ConvertUrl(requestUrl);
    return response;
}

这个方法直接在内部new了SelectPdf的HtmlToPdf类,还直接调用了它的ConvertUrl方法——这样写的话,单元测试可就麻烦了:不仅会真的发起网络请求去拉取目标URL,还会实打实调用第三方库的逻辑,这根本不是我们要的单元测试(单元测试应该只测自己写的逻辑,隔离所有外部依赖)。

那怎么改呢?核心思路就是把依赖抽象出来,用依赖注入替换掉硬编码的实例化,具体步骤是这样的:

第一步:抽象第三方依赖的接口

先定义一个接口,把我们需要用到的ConvertUrl方法暴露出来,这样不管底层用的是SelectPdf还是其他PDF转换库,我们的业务代码都不用改:

public interface IHtmlToPdfConverter
{
    PdfDocument ConvertUrl(string requestUrl);
}

第二步:写一个适配类包装SelectPdf的实现

这个类负责把SelectPdf的真实逻辑包装成我们定义的接口,相当于做个中间层:

public class SelectPdfConverterAdapter : IHtmlToPdfConverter
{
    public PdfDocument ConvertUrl(string requestUrl)
    {
        var converter = new HtmlToPdf();
        return converter.ConvertUrl(requestUrl);
    }
}

第三步:重构原来的GetPdf方法,注入依赖

把原来直接new的逻辑换成通过构造函数注入我们的接口,这样外部可以传入不同的实现(真实的或者测试用的模拟实现):

// 假设这个方法所在的类叫PdfGenerator
private readonly IHtmlToPdfConverter _converter;

// 构造函数注入依赖
public PdfGenerator(IHtmlToPdfConverter converter)
{
    _converter = converter ?? throw new ArgumentNullException(nameof(converter));
}

public PdfDocument GetPdf(string requestUrl)
{
    if (string.IsNullOrEmpty(requestUrl))
    {
        throw new ArgumentException("请求URL不能为空", nameof(requestUrl));
    }
    
    var response = _converter.ConvertUrl(requestUrl);
    return response;
}

第四步:写单元测试(用Mock框架举例,比如Moq)

现在我们可以完全模拟IHtmlToPdfConverter的行为,不用调用真实的SelectPdf,也不用发起网络请求。比如用xUnit+Moq写测试用例:

using Xunit;
using Moq;

public class PdfGeneratorTests
{
    [Fact]
    public void GetPdf_WithValidUrl_ShouldCallConvertUrlOnceAndReturnResult()
    {
        // 准备工作
        var mockConverter = new Mock<IHtmlToPdfConverter>();
        var testUrl = "https://test.example.com/page";
        var mockPdfDoc = new Mock<PdfDocument>(); // 如果PdfDocument是密封类,这里可以用null或者自定义的测试对象
        
        // 设置:当调用ConvertUrl传入testUrl时,返回我们的模拟PDF文档
        mockConverter.Setup(c => c.ConvertUrl(testUrl)).Returns(mockPdfDoc.Object);
        
        // 实例化要测试的类,传入模拟的转换器
        var pdfGenerator = new PdfGenerator(mockConverter.Object);

        // 执行测试方法
        var result = pdfGenerator.GetPdf(testUrl);

        // 验证:确认ConvertUrl确实被调用了一次,而且参数正确
        mockConverter.Verify(c => c.ConvertUrl(testUrl), Times.Once);
        // 验证返回的结果和我们模拟的一致
        Assert.Equal(mockPdfDoc.Object, result);
    }

    [Fact]
    public void GetPdf_WithEmptyUrl_ShouldThrowArgumentException()
    {
        // 准备工作
        var mockConverter = new Mock<IHtmlToPdfConverter>();
        var pdfGenerator = new PdfGenerator(mockConverter.Object);

        // 执行并验证异常
        var exception = Assert.Throws<ArgumentException>(() => pdfGenerator.GetPdf(""));
        Assert.Equal("请求URL不能为空", exception.Message);
    }
}

小补充:如果不用Mock框架怎么办?

你也可以自己写一个“假的”转换器实现,专门用于测试:

public class FakeHtmlToPdfConverter : IHtmlToPdfConverter
{
    public PdfDocument ConvertUrl(string requestUrl)
    {
        // 这里可以返回一个预先构造的PDF文档,或者根据测试需求返回特定值
        return new PdfDocument();
    }
}

测试的时候直接用这个Fake类注入就行,逻辑一样简单。

这样一来,我们的单元测试就完全隔离了外部依赖,只验证我们自己写的逻辑:比如URL参数是否正确传递,空参数是否会抛出异常,是否正确返回转换器的结果——这些才是我们要测的内容。

内容来源于stack exchange

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.08 13:33:05