Я изучаю развитие, основанное на тестах, и я заметил, что он заставляет свободно связанные объекты, что в принципе хорошо. Однако это также иногда заставляет меня предоставлять аксессуры для свойств, которые мне не нужны в обычном режиме, и я думаю, что большинство людей на SO согласны с тем, что аксессоры обычно являются признаком плохого дизайна. Это неизбежно при выполнении TDD?Как избежать доступа к объектам в тестовом режиме?
Вот пример, упрощенный чертеж код объекта без 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);
}
}
Субъект знает, как рисовать себя, что это хорошо. Все в одном месте. Тем не менее, я делаю TDD, поэтому я хочу проверить, правильно ли перемещен мой объект методом fall(), который я собираюсь реализовать. Вот что тест может выглядеть следующим образом:
@Test
public void entityFalls() {
Entity e = new Entity();
int previousY = e.getY();
e.fall();
assertTrue(previousY < e.getY());
}
Я должен смотреть на внутреннем (ну, по крайней мере, логически) состоянии объекта и посмотреть, если позиция была обновлена правильно. Так как это на самом деле так, как (я не хочу, чтобы мои тестовые примеры зависят от моей графической библиотеки), я переместил код рисования в классе «Renderer»:
class Renderer {
void drawEntity(Graphics g, Entity e) {
g.drawRect(e.getX(), e.getY(), e.getWidth(), e.getHeight());
}
}
слабосвязанной, хорошо. Я даже могу заменить средство визуализации тем, что отображает объект совершенно по-другому. Однако мне пришлось разоблачить внутреннее состояние объекта, а именно аксессоров для всех его свойств, чтобы рендеринг мог его прочитать.
Я чувствую, что это было специально вызвано TDD. Что я могу сделать по этому поводу? Является ли мой дизайн приемлемым? Требуется ли Java ключевое слово «friend» из C++?
Update:
Спасибо за ваши ценные входы до сих пор! Однако, боюсь, я выбрал плохой пример для иллюстрации моей проблемы. Это было полностью сделано, я теперь продемонстрировать тот, который ближе к моему реальному коду:
@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);
}
Это является реализация на основе игры цикл игры, в которой предприятие может упасть вниз, между прочим. Если он попадает на землю, создается новый объект.
«mockRenderer» - это макетная реализация интерфейса «Renderer». Этот дизайн был частично вынужден TDD, но также из-за того, что я собираюсь написать пользовательский интерфейс в GWT, и в браузере пока нет явного чертежа, поэтому я не думаю, что это возможно для класс Entity, чтобы взять на себя эту ответственность. Кроме того, я хотел бы сохранить возможность переноса игры на родную Java/Swing в будущем.
Update 2:
Думая об этом еще немного, может быть, это хорошо, как это. Возможно, это нормально, что объект и чертеж отделены друг от друга и что объект сообщает другим объектам достаточно о себе для рисования. Я имею в виду, как еще я мог бы достичь этого разделения? И я не вижу, как жить без него. Даже великие объектно-ориентированные программисты иногда используют объекты с геттерами/сеттерами, особенно для чего-то вроде объекта сущности. Может быть, геттер/сеттер не все злы. Как вы думаете?
Посмотрите на это так: если 'Entity' не будет' getY', вам нужно его протестировать? Теоретически, все, что недоступно для другого кода, является внутренним по отношению к 'Entity', а не к значению для пользователя, а также расширением теста. –
Но я мог бы добавить, что игры (которые, похоже, это так) являются особенно сложными для модульного теста. –
«Дружеское ключевое слово» java является модификатором доступа по умолчанию, каждый класс в одном пакете может обращаться к полям и методам, которые не имеют модификатора доступа (без публичного, частного или защищенного). Тесты могут получить доступ к этим полям, если они используют одну и ту же структуру пакета, поэтому вы можете сохранить эти данные в пакете. – josefx