首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Xna:模拟Texture2D

Xna:模拟Texture2D
EN

Stack Overflow用户
提问于 2009-08-20 20:17:32
回答 3查看 1.4K关注 0票数 4

我正在编写WinForms / Xna应用程序,我需要一些方法来抽象控制器/模型代码中与GraphicsDevice的交互。

我已经创建了一个接口IGraphicsService。我将用它来抽象一些东西,比如加载纹理。但是我不知道当我需要返回某种纹理信息时该怎么做。我应该创建一个包装Texture2D的类吗?我担心这会产生不必要的开销。从长远来看,我希望能够创建某种MockTexture2D。

这一切都是为了让我的应用更具可测试性。我不太担心速度,但如果有一些解决方案不会招致太多的开销,那就更好了,因为最终我想用它来让我的游戏更具可测试性。有什么建议吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2009-08-21 19:56:47

我个人的观点是,GraphicsDevice类太复杂了,不能被嘲笑,尽管如此,无论谁做了它,都会有更多的工作来实际指示模拟在他的测试中做正确的事情(尽管他肯定会因为努力而获得奖章:D)。

Visual Studio的“提取接口”重构只能帮你完成一半的工作。也许代码生成器可以创建一个完整的转发模拟。如果你担心性能,只要你的模拟界面反映了真实的图形设备,你可以做一些神奇的#if..#endif来在发布版本中使用真实的GraphicsDevice,并在调试版本中通过该接口?

-

无论如何,对于我自己的单元测试,我实际上是在一个不可见的表单上为我的单元测试创建一个真正的图形设备。运行我的单元测试的构建代理运行在Windows XP的VMware虚拟机中,Gentoo Linux x64作为宿主操作系统。我正在使用着色器和渲染器目标等测试实际的渲染代码。在性能方面,我也没有什么可抱怨的-- 1300个测试在10秒内执行。

这是我用来创建伪模拟图形设备服务的代码:MockedGraphicsDeviceService.cs及其单元测试:MockedGraphicsDeviceService.Test.cs

当然,缺点是您不能检查这种伪模拟图形设备中的任何期望(例如,是否发生了宽度为234、高度为456的CreateTexture()调用?)需要一些聪明的类设计来充分隔离逻辑,这样我就可以在不破坏抽象的情况下测试我的图形类。至少我可以通过这种方式获得图形代码的测试覆盖率:)

票数 3
EN

Stack Overflow用户

发布于 2009-08-22 17:31:13

您可以尝试使用Scurvy.Test来编写单元测试。这样,您根本不需要模拟图形设备,只需使用实际的实例:-)

http://scurvytest.codeplex.com

免责声明:我是该库的作者

票数 1
EN

Stack Overflow用户

发布于 2018-09-14 21:51:06

当我试图在单元测试中使用虚拟纹理时,我也遇到了这个问题。我是这样绕过它的:

代码语言:javascript
复制
internal class SneakyTexture2D : Texture2D
{
    private static readonly object Lockobj = new object();
    private static volatile Texture2D instance;

    private SneakyTexture2D()
        : this(() => throw new Exception())
    {
    }

    private SneakyTexture2D(Func<GraphicsDevice> func)
        : this(func())
    {
    }

    // Is never called
    private SneakyTexture2D(GraphicsDevice g)
        : base(g, 0, 0)
    {
    }

    // INTENTIONAL MEMORY LEAK AHOY!!!
    ~SneakyTexture2D()
    {
        instance = this;
    }


    // This is the actual "constructor"
    public static Texture2D CreateNamed(string name)
    {
        lock (Lockobj)
        {
            Texture2D local;
            instance = null;
            while ((local = instance) == null)
            {
                GC.Collect();
                GC.WaitForPendingFinalizers();

                GC.WaitForFullGCComplete();
                try
                {
                    DoNotUseMe = new SneakyTexture2D();
                }
                catch
                {
                }
            }

            local.Name = name;
            return local;
        }
    }
}

虽然SneakyTexture2D类是从Texture2D扩展而来的,但它没有调用/初始化基对象构造函数,因此不需要Graphicsdevice。

我在纹理上使用Name属性的事实有点冒险。一般来说,与未初始化的对象交互是有点危险的。

对Jon Skeets关于这个主题的精彩文章的巨大呼喊:https://codeblog.jonskeet.uk/2014/10/23/violating-the-smart-enum-pattern-in-c/

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/1308560

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档