简体   繁体   English

如何单元测试绘图图形?

[英]How to unit test drawing graphics?

My application (C#, WinForms) is a graphic editor, so drawing is a major part of functionality. 我的应用程序(C#,WinForms)是一个图形编辑器,因此绘图是功能的主要部分。 I am having difficulties unit testing logic around drawing, which makes me think that my design is wrong. 我在绘图时遇到单元测试逻辑的困难,这让我觉得我的设计是错误的。 Let me describe it and I'd like some advice on either how to unit test or how to refactor my app's logic. 让我来描述它,我想对如何进行单元测试或如何重构我的应用程序逻辑提出一些建议。

All drawing is handled by a manager (DrawingManager) which does geometric calculations and interacts with drawing canvases of controls that display the result. 所有绘图都由管理器(DrawingManager)处理,管理器进行几何计算并与显示结果的控件画布交互。 A typical method of this manager would be invoked with a reference to a drawing canvas (Graphics). 可以通过引用绘图画布(Graphics)来调用此管理器的典型方法。 Somewhere in the app's surface events (like OnPaint) we give control to the manager which decides what to draw and how, and then draws. 在应用程序的表面事件(如OnPaint)中的某个地方,我们将控制权交给经理,该经理决定要绘制什么以及如何绘制,然后绘制。 To draw, it needs to hold a reference to the Graphics object, which is why it is passed to the manager's method from the event. 要绘制,它需要保存对Graphics对象的引用,这就是它从事件传递给manager的方法的原因。

    protected override void OnPaint(PaintEventArgs e)
    {            
        IZoomBoxDrawingManager drawingManager = ServiceLocator.Instance.Resolve<IZoomBoxDrawingManager>();
        drawingManager.DrawMainImage(this, e.Graphics);
        drawingManager.DrawObjects(this, e.Graphics);

        base.OnPaint(e);
    }

Now, let's say, DrawObjects invokes either one path of logic or the other before it starts calling Graphics' methods to output the geometry. 现在,让我们说,DrawObjects在开始调用Graphics的方法输出几何之前调用逻辑路径或另一路径。 I would like to somehow unit test the logic within this manager, but its coupling with Graphics instances makes it somehow impossible, at least I don't know how to do it. 我想以某种方式对这个管理器中的逻辑进行单元测试,但它与Graphics实例的耦合使得它在某种程度上是不可能的,至少我不知道该怎么做。 Moq which I use for isolating can't mock a sealed class. 我用来隔离的Moq不能模拟密封类。 It would be sweet if I could put in some kind of registrator instead of Graphics and be able to see what methods of Graphics are invoked and when. 如果我可以放入某种registrator而不是Graphics并且能够看到调用Graphics的方法以及何时调用,那将是很好的。 Please advise! 请指教!

Consider using the Adapter pattern to wrap the functionality needed by the Graphics object in an interface. 考虑使用Adapter模式来包装Graphics对象在接口中所需的功能。

interface IGraphics
{
    void DrawCircle(int x,int y,int d);
}

public class GraphicsAdapter : IGraphics
{
    private readonly Graphics graphics;

    public GraphicsAdapter(Graphics g)
    {
        this.graphics = g;
    }

    public void DrawCircle(int x, int y, int d)
    {
        graphics.DrawCircle(x, y, d);
    }
}

Now your DrawingManager can have a dependency on the IGraphics interface instead of the sealed Graphics object. 现在,您的DrawingManager可以依赖于IGraphics接口而不是密封的Graphics对象。 You can mock it during testing but use the adapter at runtime: 您可以在测试期间模拟它,但在运行时使用适配器:

drawingManager.DrawObjects(this, new GraphicsAdapter(e.Graphics));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM