I'm new to unit testing, and to learn, I've decided to "contribute" to Monogame to help with their testing efforts. The issue at hand is to test the input device classes. I've started with the GamePad class.
Here are the tests that I have implemented.
namespace MonoGame.Tests
{
[TestFixture]
public class GamePadTests
{
private Array GetPlayerIndexes() // gets a list of enum values to test
{
return Enum.GetValues(typeof(PlayerIndex));
}
private Array GetGamePadDeadZoneIndexes()
{
return Enum.GetValues(typeof(GamePadDeadZone));
}
[Test] // generate tests for each PlayerIndex enum value
public void GetCapabilities_ShouldNotReturnNull_GivenPlayerIndex([ValueSource("GetPlayerIndexes")] PlayerIndex pi)
{
Assert.IsNotNull(GamePad.GetCapabilities(pi));
}
[Test] // generate tests for each PlayerIndex enum value
public void GetCapabilities_ShouldReturnGamePadCapabilities_GivenPlayerIndex([ValueSource("GetPlayerIndexes")] PlayerIndex pi)
{
Assert.IsInstanceOf<GamePadCapabilities>(GamePad.GetCapabilities(pi));
}
[Test]
public void GetCapabilies_ShouldNotReturnNull_GivenInt([Range(-1, 4)] int i) // range to test negative, PlayerIndex, and higher values
{
Assert.IsInstanceOf<GamePadCapabilities>(GamePad.GetCapabilities(i));
}
[Test]
public void GetCapabilities_ShouldReturnGamePadCapabilities_WhenGivenInt([Range(-1, 4)] int i) // range to test negative, PlayerIndex, and higher values
{
Assert.IsInstanceOf<GamePadCapabilities>(GamePad.GetCapabilities(i));
}
[Test] // generate tests for each PlayerIndex enum value
public void GetState_ShouldNotReturnNull_WhenGivenPlayerIndex([ValueSource("GetPlayerIndexes")] PlayerIndex pi)
{
Assert.IsNotNull(GamePad.GetState(pi));
}
[Test] // generate tests for each PlayerIndex enum value
public void GetState_ShouldReturnGamePadState_WhenGivenPlayerIndex([ValueSource("GetPlayerIndexes")] PlayerIndex pi)
{
Assert.IsInstanceOf<GamePadState>(GamePad.GetState(pi));
}
[Test]
public void GetState_ShouldNotReturnNull_WhenGivenInt([Range(-1, 4)] int i) // range to test negative, PlayerIndex, and higher values
{
Assert.IsNotNull(GamePad.GetState(i));
}
[Test]
public void GetState_ShouldReturnGamePadState_WheGivenInt([Range(-1, 4)] int i) // range to test negative, PlayerIndex, and higher values
{
Assert.IsInstanceOf<GamePadState>(GamePad.GetState(i));
}
[Test]
public void GetState_ShouldNotReturnNull_WhenGivenPlayerIndex_GamePadDeadZone(
[ValueSource("GetPlayerIndexes")] PlayerIndex pi, // generate tests for each combination of PlayerIndex and GamePadDeadZone enum values
[ValueSource("GetGamePadDeadZoneIndexes")] GamePadDeadZone gpdz
)
{
Assert.IsNotNull(GamePad.GetState(pi, gpdz));
}
[Test]
public void GetState_ShouldReturnGamePadState_WhenGivenPlayerIndex_GamePadDeadZone(
[ValueSource("GetPlayerIndexes")] PlayerIndex pi, // generate tests for each combination of PlayerIndex and GamePadDeadZone enum values
[ValueSource("GetGamePadDeadZoneIndexes")] GamePadDeadZone gpdz
)
{
Assert.IsInstanceOf<GamePadState>(GamePad.GetState(pi, gpdz));
}
[Test]
public void GetState_ShouldNotReturnNull_WhenGivenInt_GamePadDeadZone(
[Range(-1, 4)] int i, // generate tests for each combination of the index range and GamePadDeadZone enum values
[ValueSource("GetGamePadDeadZoneIndexes")] GamePadDeadZone gpdz
)
{
Assert.IsNotNull(GamePad.GetState(i, gpdz));
}
[Test]
public void GetState_ShouldReturnGamePadState_WhenGivenInt_GamePadeDeadZone(
[Range(-1, 4)] int i, // generate tests for each combination of the index range and GamePadDeadZone enum values
[ValueSource("GetGamePadDeadZoneIndexes")] GamePadDeadZone gpdz
)
{
Assert.IsInstanceOf<GamePadState>(GamePad.GetState(i, gpdz));
}
[Test]
public void SetVibration_ShouldNotReturnNull_WhenGivenPlayerIndex_Float_Float(
[ValueSource("GetPlayerIndexes")] PlayerIndex pi, // generate tests for each combination of the PlayerIndex enum values and both float ranges
[Range(0.0f, 1.0f, 0.25f)] float lm,
[Range(0.0f, 1.0f, 0.25f)] float rm
)
{
Assert.IsNotNull(GamePad.SetVibration(pi, lm, rm));
}
[Test]
public void SetVibration_ShouldReturnBool_WhenGivenPlayerIndex_Float_Float(
[ValueSource("GetPlayerIndexes")] PlayerIndex pi, // generate tests for each combination of the PlayerIndex enum values and both float ranges
[Range(0.0f, 1.0f, 1.0f)] float lm,
[Range(0.0f, 1.0f, 1.0f)] float rm
)
{
Assert.IsInstanceOf<bool>(GamePad.SetVibration(pi, lm, rm));
}
[Test]
public void MaximumGamePadCount_ShouldNotReturnNull_WhenGet()
{
Assert.IsNotNull(GamePad.MaximumGamePadCount);
}
[Test]
public void MaximumGamePadCount_ShouldReturnInt_WhenGet()
{
Assert.IsInstanceOf<int>(GamePad.MaximumGamePadCount);
}
}
}
For your information, here's the code under test, the GamePad
class,
and this is not to be reviewed, please consider it as given:
namespace Microsoft.Xna.Framework.Input
{
/// <summary>
/// Supports querying the game controllers and setting the vibration motors.
/// </summary>
public static partial class GamePad
{
/// <summary>
/// Returns the capabilites of the connected controller.
/// </summary>
/// <param name="playerIndex">Player index for the controller you want to query.</param>
/// <returns>The capabilites of the controller.</returns>
public static GamePadCapabilities GetCapabilities(PlayerIndex playerIndex)
{
return GetCapabilities((int)playerIndex);
}
/// <summary>
/// Returns the capabilites of the connected controller.
/// </summary>
/// <param name="index">Index for the controller you want to query.</param>
/// <returns>The capabilites of the controller.</returns>
public static GamePadCapabilities GetCapabilities(int index)
{
if (index < 0 || index >= PlatformGetMaxNumberOfGamePads())
return new GamePadCapabilities();
return PlatformGetCapabilities(index);
}
/// <summary>
/// Gets the current state of a game pad controller with an independent axes dead zone.
/// </summary>
/// <param name="playerIndex">Player index for the controller you want to query.</param>
/// <returns>The state of the controller.</returns>
public static GamePadState GetState(PlayerIndex playerIndex)
{
return GetState((int)playerIndex, GamePadDeadZone.IndependentAxes);
}
/// <summary>
/// Gets the current state of a game pad controller with an independent axes dead zone.
/// </summary>
/// <param name="index">Index for the controller you want to query.</param>
/// <returns>The state of the controller.</returns>
public static GamePadState GetState(int index)
{
return GetState(index, GamePadDeadZone.IndependentAxes);
}
/// <summary>
/// Gets the current state of a game pad controller, using a specified dead zone
/// on analog stick positions.
/// </summary>
/// <param name="playerIndex">Player index for the controller you want to query.</param>
/// <param name="deadZoneMode">Enumerated value that specifies what dead zone type to use.</param>
/// <returns>The state of the controller.</returns>
public static GamePadState GetState(PlayerIndex playerIndex, GamePadDeadZone deadZoneMode)
{
return GetState((int)playerIndex, deadZoneMode);
}
/// <summary>
/// Gets the current state of a game pad controller, using a specified dead zone
/// on analog stick positions.
/// </summary>
/// <param name="index">Index for the controller you want to query.</param>
/// <param name="deadZoneMode">Enumerated value that specifies what dead zone type to use.</param>
/// <returns>The state of the controller.</returns>
public static GamePadState GetState(int index, GamePadDeadZone deadZoneMode)
{
if (index < 0 || index >= PlatformGetMaxNumberOfGamePads())
return GamePadState.Default;
return PlatformGetState(index, deadZoneMode);
}
/// <summary>
/// Sets the vibration motor speeds on the controller device if supported.
/// </summary>
/// <param name="playerIndex">Player index that identifies the controller to set.</param>
/// <param name="leftMotor">The speed of the left motor, between 0.0 and 1.0. This motor is a low-frequency motor.</param>
/// <param name="rightMotor">The speed of the right motor, between 0.0 and 1.0. This motor is a high-frequency motor.</param>
/// <returns>Returns true if the vibration motors were set.</returns>
public static bool SetVibration(PlayerIndex playerIndex, float leftMotor, float rightMotor)
{
return SetVibration((int)playerIndex, leftMotor, rightMotor);
}
/// <summary>
/// Sets the vibration motor speeds on the controller device if supported.
/// </summary>
/// <param name="index">Index for the controller you want to query.</param>
/// <param name="leftMotor">The speed of the left motor, between 0.0 and 1.0. This motor is a low-frequency motor.</param>
/// <param name="rightMotor">The speed of the right motor, between 0.0 and 1.0. This motor is a high-frequency motor.</param>
/// <returns>Returns true if the vibration motors were set.</returns>
public static bool SetVibration(int index, float leftMotor, float rightMotor)
{
if (index < 0 || index >= PlatformGetMaxNumberOfGamePads())
return false;
return PlatformSetVibration(index, MathHelper.Clamp(leftMotor, 0.0f, 1.0f), MathHelper.Clamp(rightMotor, 0.0f, 1.0f));
}
/// <summary>
/// The maximum number of game pads supported on this system. Attempting to
/// access a gamepad index higher than this number will result in an <see cref="InvalidOperationException"/>
/// being thrown by the API.
/// </summary>
public static int MaximumGamePadCount
{
get { return PlatformGetMaxNumberOfGamePads(); }
}
}
}
The problem at hand is that I'm not sure that I've actually done anything other some null and type checking and "interface verification". I spoke with someone on the project and they said that I'm generally not allowed to mock or change other code to aid in testing. Not that I know much about mocking particularly. I just don't know if I can do any more substantial testing to this class.
Is this about the expected form for unit testing? Is there more I can do to test this class in general or improve my code?