I have defined the following Unit-Test:
[TestMethod] //@Test for the Java crowd
public void In_The_Beginning_All_The_Board_Is_Black()
{
IBoard board = new Board(new Size(10, 22));
BoardEngine boardEngine = new BoardEngine(board);
for (int y = 0; y < boardEngine.Size.Width; ++y)
{
for (int x = 0; x < boardEngine.Size.Width; ++x)
{
Assert.AreEqual<Color>(Color.Black, boardEngine.GetCellAt(new Point(x, y)).Color);
}
}
}
Now, the problem is that currently everything is simple and I can instantiate Board as it’s shown, passing it its size in the constructor. I know later I’ll have a way more complex Board, that has lots of dependencies, so I’d like to try to write out this test with a mock instead. The issue is that I don’t get how. What should I setup with this mock?
The behaviour I want to test is that when a BoardEngine is instantiated, all the cells of the board must have its color set to black. How can I represent that in a test with a Mock instead of the Board class?
Internally, I currently just have an IBoard field in BoardEngine:
public class BoardEngine {
IBoard board;
...
public BoardEngine(IBoard board) {
this.board = board;
SetAllCellsToBlack();
}
private void SetAllCellsToBlack() {
board.SetAllCellsTo(Color.Black);
}
...
}
and IBoard is defined as follows:
public interface IBoard
{
Size Size { get; }
BoardCell GetCellAt(Point location);
void SetCellAt(Point location, BoardCell cell);
void SetAllCellsTo(Color color);
}
Am I taking the right approach here? Maybe the problem is that as BoardEngine is basically delegating all its work to IBoard, I should be testing an IBoard implementation and not BoardEngine?
Edit
So, if I’m understanding correctly what you guys are trying to tell me, I have 2 options:
- I can make (what I think would be, correct me if I’m wrong) Unit-Tests of both the BoardEngine and the Board. The BoardEngine’s Unit-Test will just check whenever the call is being correctly implemented, using a Mock object of the Board. The Board’s Unit-Test doesn’t actually need a mock and just checks that when I run SetAllCellsTo(Color color) it will really turn them that color. With this, I am testing the behaviour.
- What I actually have, a test that tests the state after instantiating a boardEngine with a Board instance, checking all the board cells to see if they are black. Here, I am testing the state.
Is this correct?
Also, when using TDD, which tests should I do first? I’d say tests of type 1. When should I use tests of type 2?
Thanks
This is going to vary depending on the mocking framework that you’re using. With Rhino.Mocks, it would look like this:
Here you create the mock or stub, do what you’re testing, and then assert that the expected thing happened. In this case, you’re expecting
SetAllCellsTo(Color.Black)to be called once.You’re not concerned with whether all the cells are now black, because that is behaviour outside of the unit — outside, even, of the class under test, which in this case is
BoardEngine. All you’re testing is thatBoardEnginecalls the specified method on the injected dependency when it is instantiated.edit in response to OP edit
The two options you outline in your edit are correct, but not mutually exclusive. I recommend that you have unit tests in place to be sure that each piece of functionality works as expected across various entry conditions, and tests that make sure the interaction works at a higher level.
Keep in mind that you can cover the bases by (1) testing that a call to
board.SetAllCellsTo(Color.Black)actually works, independent ofBoardEngine, and then (2) testing thatBoardEnginecalls that [tested to be working] method. Still, you should have higher-level tests to ensure that everything actually plays together as expected without side effects.What test to start with is a bit subjective. In terms of driving out functionality with TDD, you need to have a good idea of how you want the system to work — how
BoardEngineandBoardwill work together. You could define both interfaces and outline a test, but you can’t actually execute the test until you’ve implemented both interfaces, and if you write the test you won’t be able to compile it because you’ll have no classes to instantiate. On the other hand, you can write unit tests as you implement each interface. Start withIBoardbecause it has fewer dependencies. Start implementingBoard : IBoardand cover it as you go. When you know that a call toSetAllColorsTo()works as expected, you’ll be more comfortable with a unit test of theBoardEngineconstructor calling that method.