Hey guys,
So a while back I decided I wanted to try to release a game since it’s something I’ve always wanted to do. I think I’m even, maybe, getting fairly close to doing that (lol :P). One of the goals I set out with this project though is that I wanted to ensure that all of the code I write is backed by unit tests.
Since the XNA framework (and by extension, MonoGame) was never really designed with unit testing/mocking in mind, I’ve ended up creating several wrappers for MonoGame objects so that I can interact with code at a more abstract level. This is generally fairly easy to achieve, involving creating an interface from the existing object and then implementing that interface with a wrapper for the MonoGame object. Your code can then interact with the interface, allowing you to easily mock it in a unit test.
Here’s a very brief example of an object responsible for drawing a texture with various parameters. Utilizing the wrappers, I can then write a unit test to ensure that the draw call does the expected things. In this way, if I ever change the code to include more functionality, I can have confidence that my intended functionality still works… or doesn’t, resulting in a bunch of failed tests that I can then either address by correcting, or updating the tests.
// Sample object
public class SimpleGameDrawable
{
private ISpriteBatch _spriteBatch;
private ITexture2D _texture;
public Vector2 Location { get; set; } = Vector2.Zero;
public Color Color { get; set; } = Color.White;
public SimpleGameDrawable(ISpriteBatch spriteBatch, ITexture2D texture)
{
_spriteBatch = spriteBatch ?? throw new ArgumentNullException();
_texture = texture ?? throw new ArgumentNullException();
}
public void Draw(GameTime gameTime)
{
_spriteBatch.Begin();
_spriteBatch.Draw(_texture, this.Location, this.Color;
_spriteBatch.End();
}
}
// Sample test class using MSTEST and NSubstitute for mocking
[TestClass]
public class SimpleGameDrawable_Tests
{
private SimpleGameDrawable _sut;
private ISpriteBatch _mockSpriteBatch;
private ITexture2D _mockTexture;
[TestInitialize]
public void Initialize()
{
_mockSpriteBatch = Substitute.For<ISpriteBatch>();
_mockTexture = Substitute.For<ITexture2D>();
_sut = new SimpleGameDrawable(_mockSpriteBatch, _mockTexture)
{
Location = new Vector2(123, 321),
Color = Color.Pink,
};
}
[TestMethod]
public void DrawShouldBeginThenEndSpriteBatch()
{
_sut.Draw(new GameTime());
Received.InOrder(
() =>
{
_mockSpriteBatch.Begin();
_mockSpriteBatch.End();
}
);
}
[TestMethod]
public void DrawShouldCallSpriteBatchDrawWithExpectedParameters()
{
_sut.Draw(new GameTime());
_mockSpriteBatch.Received(1).Draw(_mockTexture, new Vector2(123, 321), Color.Pink);
}
}
Anyway, this has been an ongoing development so the wrapper is by no means complete… my approach is to just implement the things I need to achieve my goals, then stop there. That said, I’m wondering if this is something that would interest other people. I currently have this code sitting in a private repository with the rest of my stuff, but if there were interest I could upload it to github or something, as well as continue the project to include functionality I currently don’t use. I could probably also write up some tutorials on applying testing to MonoGame development.
Any thoughts on this?