I'm learning test-driven development, and I have noticed that it forces loosely coupled objects, which is basically a good thing. However, this also sometimes forces me to provide accessors for properties I wouldn't need normally, and I think most people on SO agree that accessors are usually a sign of bad design. Is this inevitable when doing TDD?
Here is an example, the simplified drawing code of an entity without TDD:
class Entity {
private int x;
private int y;
private int width;
private int height;
void draw(Graphics g) {
g.drawRect(x, y, width, height);
}
}
The entity knows how to draw itself, that's good. All in one place. However, I'm doing TDD, so I want to check whether my entity was moved correctly by the "fall()" method I am about to implement. Here is what the test case could look like:
@Test
public void entityFalls() {
Entity e = new Entity();
int previousY = e.getY();
e.fall();
assertTrue(previousY < e.getY());
}
I have to look at the object's internal (well, at least logically) state and see if the position was updated correctly. Since it's actually in the way (I don't want my test cases to depend on my graphics library), I moved the drawing code to a class "Renderer":
class Renderer {
void drawEntity(Graphics g, Entity e) {
g.drawRect(e.getX(), e.getY(), e.getWidth(), e.getHeight());
}
}
Loosely coupled, good. I can even replace the renderer with one that displays the entity in a completely different way. However, I had to expose the internal state of the entity, namely the accessors for all of its properties, so that the renderer could read it.
I feel that this was specifically forced by TDD. What can I do about this? Is my design acceptable? Does Java need the "friend" keyword from C++?
Update:
Thanks for your valuable inputs so far! However, I fear I have chosen a bad example for illustrating my issue. This was completely made up, I will now demonstrate one that is closer to my actual code:
@Test
public void entityFalls() {
game.tick();
Entity initialEntity = mockRenderer.currentEntity;
int numTicks = mockRenderer.gameArea.height
- mockRenderer.currentEntity.getHeight();
for (int i = 0; i < numTicks; i++)
game.tick();
assertSame(initialEntity, mockRenderer.currentEntity);
game.tick();
assertNotSame(initialEntity, mockRenderer.currentEntity);
assertEquals(initialEntity.getY() + initialEntity.getHeight(),
mockRenderer.gameArea.height);
}
This is a game loop based implementation of a game where an entity can fall down, among other things. If it hits the ground, a new entity is created.
The "mockRenderer" is a mock implementation of an interface "Renderer". This design was partly forced by TDD, but also because of the fact that I'm going to write the user interface in GWT, and there is no explicit drawing in the browser (yet), so I don't think it is possible for the Entity class to assume that responsibility. Furthermore, I would like to keep the possibility of porting the game to native Java/Swing in the future.
Update 2:
Thinking about this some more, maybe it's okay how it is. Maybe it's okay that the entity and the drawing is separated and that the entity tells other objects enough about itself to be drawn. I mean, how else could I achieve this separation? And I don't really see how to live without it. Even great object-oriented programmers use objects with getters/setters sometimes, especially for something like an entity object. Maybe getter/setter are not all evil. What do you think?