@Trinith wrote:
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?
Posts: 1
Participants: 1