我正在尝试在 monogame 之上建立一个框架。我真的希望该框架可以进行单元测试。
比如我写过一个
SpriteComponent
的课。如果我可以创建一个快速测试来验证组件的 OffsetType
属性是否有效,那就太好了。像这样的东西:
[Fact]
public void SpriteOffsetTypeWorks()
{
AminoGame game = new AminoGame();
Scene scene = new Scene(game);
Entity entity = new Entity(scene);
SpriteComponent sprite = new SpriteComponent(entity);
sprite.OffsetType = AnchorType.Centre;
Assert.Equal(new Vector2(0.5f, 0.5f), sprite.OffsetFactor);
}
对于上下文,
AminoGame
继承自Monogame的Game
类。
问题在于,虽然
Game
中固有的某些服务在单元测试中正确初始化,但其他服务却没有,特别是 GraphicsDevice
。这是有道理的,因为我的单元测试没有创建图形环境。
为了尝试解决这个问题,我
SpriteComponent
中删除了所有“渲染”代码,并将其放置在其他地方,在一个不会在非图形设置中调用的代码区域。AminoGame
的接口,但我也可以环绕一个虚拟类,我将在单元测试中使用它。这种做法还是有问题的。例如:
public class SpriteComponent : Component
{
public Texture2D Texture => _texture;
protected Texture2D _texture;
public SpriteComponent(Entity owner) : base(owner)
{
if (Config.DefaultSprite == null)
{
throw new InvalidOperationException($"Cannot call {nameof(SpriteComponent)} constructor with unspecified sprite: Specify a default sprite in {nameof(Config.DefaultSprite)}.");
}
_texture = World.Content.Load<Texture2D>(Config.DefaultSprite);
}
}
我编写的
SpriteComponent
类能够在未指定纹理的情况下加载默认纹理。但是 Texture2D
是一个图形对象,所以 Monogame 再次抱怨它在尝试加载时没有 GraphicsDevice
。
这让我想知道:我是否想要在单元测试中使用纹理或 3D 模型?如果没有,那我怎么写
SpriteComponent
的方式完全可以在没有图形的情况下运行?
但更广泛地说,我还依赖哪些其他服务,我不知道,在单元测试中不可用?
我的方法是错误的吗?有更好的方法吗?
所以,老实说,我根本不知道 monogame。但这些年来我使用了数十种框架,其中大多数在单元测试方面都很糟糕。问题是,当您将代码与框架分离到足以对其进行单元测试时,您通常会失去在该框架中编码的大部分优势。你的代码变得非常臃肿,主要是因为它不能使用框架并进行单元测试。
有些框架内置了可单元测试的模拟(这些很好!)但不是特别常见。快速谷歌搜索导致:https://community.monogame.net/t/unit-testing-best-practices/2638/2,这并不是特别令人鼓舞。基本上,我的经验法则是,如果一个框架需要继承,单元测试将很难(因为你不能注入模拟/存根)。集成测试很可能是您最好的方法。