ScottPlot 单元测试工具:ImageComparer 与视觉回归测试实践

ScottPlot 单元测试工具:ImageComparer 与视觉回归测试实践

【免费下载链接】ScottPlot ScottPlot: 是一个用于.NET的开源绘图库,它简单易用,可以快速创建各种图表和图形。 【免费下载链接】ScottPlot 项目地址: https://gitcode.com/gh_mirrors/sc/ScottPlot

引言:为什么视觉回归测试对绘图库至关重要

在软件开发中,单元测试(Unit Testing)是保障代码质量的重要手段,但对于绘图库而言,传统的数值比较测试往往难以覆盖所有视觉呈现效果。ScottPlot作为一个功能强大的.NET绘图库,其核心价值在于生成高质量、精确的图表。然而,即使代码逻辑正确,微小的渲染变化也可能导致图表质量下降。这就是视觉回归测试(Visual Regression Testing)的用武之地。

视觉回归测试通过比较不同版本软件生成的图像,检测视觉呈现上的差异。在ScottPlot中,这一过程通过ImageComparer工具和ImageDiff类实现,为开发者提供了自动化的视觉质量保障机制。本文将深入探讨ScottPlot的视觉回归测试框架,帮助开发者充分利用这一工具提升图表质量。

ScottPlot视觉回归测试框架概述

ScottPlot的视觉回归测试框架主要由以下核心组件构成:

mermaid

这三个核心类协同工作,实现了从单图像比较到批量文件夹分析的完整视觉测试流程。

ImageDiff:图像差异分析的核心算法

ImageDiff类是视觉比较的核心,它负责分析两张图像之间的差异并量化结果。让我们通过一个实际测试案例来了解其工作原理:

[Test]
public void Test_Image_Diff()
{
    Image img1 = new("TestImages/bag_frame1.png");
    Image img2 = new("TestImages/bag_frame2.png");
    ScottPlot.Testing.ImageDiff diff = new(img1, img2);

    diff.PercentOfDifferencePixels.Should().BeApproximately(17.94, .01);
    diff.NumberOfDifferentPixels.Should().Be(1601);
    diff.DifferenceImage?.SaveTestImage();
}

在这个测试中,ImageDiff类计算了两个图像之间的差异像素数量及其占比,并生成了差异图像。这种量化分析使得视觉差异变得可测量、可测试,为自动化测试提供了基础。

ImageDiff的工作流程可以概括为:

mermaid

ImageComparer:可视化图像比较工具

虽然ImageDiff提供了量化分析,但开发者通常需要直观地查看差异所在。ImageComparer用户控件正是为此设计的,它提供了交互式的图像比较界面。

核心功能解析

ImageComparer的构造函数初始化了一系列交互组件:

public ImageComparer()
{
    InitializeComponent();

    timer1.Enabled = !DesignMode;
    timer1.Tick += (s, e) => SwitchImages(1);
    timer1.Interval = 100;
    pictureBox1.MouseWheel += (s, e) => SwitchImages(e.Delta > 0 ? 1 : -1);

    checkBox1.CheckedChanged += (s, e) => timer1.Enabled = checkBox1.Checked;
    checkBox2.CheckedChanged += (s, e) => UpdateDiffBitmap();

    pictureBox1.DoubleClick += (s, e) => System.Diagnostics.Process.Start("explorer.exe", Path1!);
    pictureBox2.DoubleClick += (s, e) => System.Diagnostics.Process.Start("explorer.exe", Path2!);
}

这段代码揭示了ImageComparer的几个关键交互特性:

  1. 图像切换:通过定时器自动切换或鼠标滚轮手动切换两张图像,便于对比差异
  2. 差异可视化:通过复选框控制差异图像的显示方式
  3. 文件定位:双击图像可在资源管理器中定位源文件

图像切换机制

SwitchImages方法实现了图像切换逻辑:

private void SwitchImages(int delta)
{
    ImageMode += delta;
    if (ImageMode % 2 == 0)
    {
        SetBitmap1();
    }
    else
    {
        SetBitmap2();
    }
}

这种设计允许开发者快速切换查看基准图像和测试图像,通过视觉闪烁效果突出差异区域。

差异图像生成

UpdateDiffBitmap方法控制差异图像的显示:

private void UpdateDiffBitmap()
{
    if (ImgDiff is null)
        return;

    ScottPlot.Image? diffImage = checkBox2.Checked
        ? ImgDiff.DifferenceImage!.GetAutoscaledImage()
        : ImgDiff.DifferenceImage;

    pictureBox2.Image = (diffImage is not null)
        ? ScottPlot.WinForms.FormsPlotExtensions.GetBitmap(diffImage)
        : null;
}

这里的GetAutoscaledImage()方法可能是对差异图像进行增强处理,使微小差异更明显,这对于检测细微的视觉变化非常重要。

FolderComparisonResults:批量图像比较

在实际开发中,往往需要比较大量图像(如整个测试套件的输出)。FolderComparisonResults类提供了批量处理能力:

public FolderComparisonResults(string before, string after)
{
    BeforeFolder = before;
    AfterFolder = after;
    var BeforePaths = Directory.GetFiles(before, "*.png");
    var AfterPaths = Directory.GetFiles(after, "*.png");

    HashSet<string> allFilenames = [];
    allFilenames.UnionWith(BeforePaths.Select(x => Path.GetFileName(x)));
    allFilenames.UnionWith(AfterPaths.Select(x => Path.GetFileName(x)));
    Filenames = allFilenames.Order().ToArray();

    Summaries = new string[Filenames.Length];
    ImageDiffs = new ScottPlot.Testing.ImageDiff?[Filenames.Length];
}

这个构造函数收集两个文件夹中的所有图像文件,为后续比较做准备。Analyze方法则处理具体的比较逻辑:

public void Analyze(int i)
{
    string pathBefore = GetPath1(i);
    string pathAfter = GetPath2(i);

    bool img1Exists = File.Exists(pathBefore);
    bool img2Exists = File.Exists(pathAfter);

    if (img1Exists && img2Exists)
    {
        ScottPlot.Image img1 = new(pathBefore);
        ScottPlot.Image img2 = new(pathAfter);
        if (img1.Size != img2.Size)
        {
            Summaries[i] = "resized";
            return;
        }
        ImageDiffs[i] = new(img1, img2, saveDiffImage: false);
        Summaries[i] = ImageDiffs[i]!.TotalDifference == 0 ? "unchanged" : "changed";
    }
    else if (img1Exists && !img2Exists)
    {
        Summaries[i] = "deleted";
    }
    else if (!img1Exists && img2Exists)
    {
        Summaries[i] = "added";
    }
    else
    {
        throw new InvalidOperationException("neither file exists");
    }
}

这个方法处理了多种可能的情况:

  • 图像大小不匹配
  • 图像内容变化
  • 图像新增
  • 图像删除

通过这种批量分析,开发者可以快速了解代码更改对整个图表库视觉呈现的影响。

实际应用:如何在ScottPlot开发中使用视觉回归测试

测试工作流

ScottPlot的视觉回归测试工作流可以概括为:

mermaid

实施建议

  1. 建立基准图像库:为每个测试用例生成高质量的基准图像,存储在版本控制系统中

  2. 集成到CI/CD流程:在持续集成过程中自动运行视觉测试,及时发现视觉回归

  3. 设置合理的差异阈值:根据图表类型设置适当的差异容忍度,避免误报

  4. 定期更新基准图像:当有意更改图表样式时,更新基准图像并记录更改原因

高级技巧与最佳实践

提高测试效率

  • 并行测试:同时比较多个图像对,加快测试速度
  • 增量测试:只重新生成受代码更改影响的图像
  • 分层测试:先进行快速的缩略图比较,再对差异图像进行全分辨率分析

处理常见挑战

  1. 抗锯齿差异:不同硬件或渲染引擎可能导致轻微的抗锯齿差异,可通过模糊比较或忽略边缘像素解决

  2. 文本渲染差异:不同系统上的字体渲染可能不同,考虑使用矢量文本或图像哈希比较

  3. 性能优化:对于大型图像,可先缩小尺寸再比较,提高测试速度

自定义比较规则

根据具体需求,可以扩展ImageDiff类实现自定义比较规则:

public class CustomImageDiff : ImageDiff
{
    public double Tolerance { get; set; } = 0.5; // 允许的最大像素差异
    
    public bool IsAcceptableDifference()
    {
        // 自定义逻辑,例如忽略某些区域或特定类型的差异
        return PercentOfDifferencePixels < Tolerance;
    }
}

结论:视觉回归测试如何提升ScottPlot质量

视觉回归测试在ScottPlot开发中扮演着关键角色,它提供了传统单元测试无法实现的视觉质量保障。通过ImageDiff的量化分析、ImageComparer的直观比较和FolderComparisonResults的批量处理,开发者可以:

  1. 及早发现视觉缺陷:在开发过程中快速检测到代码更改导致的视觉问题

  2. 提高代码质量:为渲染代码提供安全网,鼓励开发者大胆重构和优化

  3. 减少手动检查工作:自动化繁琐的视觉检查过程,提高开发效率

  4. 保障用户体验:确保最终用户获得一致、高质量的图表渲染效果

随着ScottPlot的不断发展,视觉回归测试将继续发挥重要作用,帮助团队在添加新功能的同时,保持图表渲染的稳定性和高质量。

附录:快速入门指南

1. 设置基准图像

// 生成并保存基准图像
var plt = new ScottPlot.Plot(400, 300);
plt.AddSignal(ScottPlot.DataGen.Sin(100));
plt.SaveFig("基准图像/正弦波.png");

2. 运行视觉测试

// 比较两个图像文件夹
var comparer = new FolderComparisonResults("基准图像", "新图像");
for (int i = 0; i < comparer.Filenames.Length; i++)
{
    comparer.Analyze(i);
    Console.WriteLine($"{comparer.Filenames[i]}: {comparer.Summaries[i]}");
}

3. 使用ImageComparer查看差异

// 在Windows应用程序中显示图像比较器
var form = new Form();
var imageComparer = new ImageComparer();
imageComparer.SetImages("基准图像/正弦波.png", "新图像/正弦波.png");
form.Controls.Add(imageComparer);
form.ShowDialog();

通过这些工具和技术,ScottPlot团队能够确保图表渲染质量的稳定性,为用户提供可靠、美观的数据可视化体验。

【免费下载链接】ScottPlot ScottPlot: 是一个用于.NET的开源绘图库,它简单易用,可以快速创建各种图表和图形。 【免费下载链接】ScottPlot 项目地址: https://gitcode.com/gh_mirrors/sc/ScottPlot

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值