Нужно ли мне сначала менять уже работающие тесты и только потом пытаться запустить новый? - PullRequest
2 голосов
/ 26 июля 2010

У меня есть куча тестов, которые предполагают, что мой класс Tetris составлен из класса Board.Теперь я чувствую, что вместо того, чтобы иметь Board внутри этого Tetris класса, я хочу иметь Board внутри BoardEngine класса, который находится внутри Tetris класса.Вот что просит этот тест:

    [TestMethod]
    public void Start_Game_And_Check_That_A_Red_Cube_Appears_And_Moves_Down_One_Pixel_On_First_Iteration() {
        Board board = new Board(10, 22);
        BoardEngine boardEngine = new BoardEngine(board);
        Tetris tetris = new Tetris(boardEngine);

        //test that the pixels are black/empty at first
        Assert.AreNotEqual(Color.Red, tetris.GetColorAt(0, 0));
        Assert.AreNotEqual(Color.Red, tetris.GetColorAt(1, 0));

        tetris.Start();
 //and that after running Start() the pixels are set to red
        Assert.AreEqual(Color.Red, tetris.GetColorAt(0, 0));
        Assert.AreEqual(Color.Red, tetris.GetColorAt(1, 0));
    }

Итак, чтобы запустить этот код, мне сначала нужно было создать класс BoardEngine.После этого мне нужен пустой конструктор BoardEngine, который принимает Board в качестве аргумента.Затем мне нужно создать пустой новый конструктор на Tetris, который принимает BoardEngine в качестве аргумента.

Если я попытаюсь запустить код, я получу NullPointerException.Зачем?Потому что при попытке сделать

tetris.GetColorAt(0, 0)

, поскольку в этом конструкторе, который я использую сейчас, я не установил Board в Tetris для чего-либо, он просто взорвется.

Мой первый вопрос возникает здесь.Что делать сейчас?С одной стороны, я могу сделать так, чтобы это не вылетало, установив что-то на Board.С другой стороны, что я действительно хочу, так это не устанавливать что-либо, я хочу в конечном итоге избавиться от него, поэтому мой класс Tetris имеет только атрибут BoardEngine.

Должен ли я пойти и провести рефакторинг самих тестов?Я думаю, что это единственный способ сделать эту работу.Я что-то пропустил?В какое время я должен провести рефакторинг других тестов?Если я проведу рефакторинг, прежде чем пытаться запустить этот тест, я смогу сохранить все остальные тесты зелеными, а этот - красным.С другой стороны, если я попытаюсь сделать это как можно скорее зеленым, все остальные станут красными: (

Вот пример старого теста:

[TestMethod]
public void ...() {
    Board board = new Board(10, 22);
    Tetris tetris = new Tetris(board);

    tetris.Start();
    Assert.AreEqual(Color.Red, board.GetColorAt(0, 0));
    Assert.AreEqual(Color.Red, board.GetColorAt(1, 0));
}

Спасибо

Ответы [ 4 ]

2 голосов
/ 26 июля 2010

Этот код:

Board board = new Board(10, 22);
Tetris tetris = new Tetris(board);

будет работать нормально, если вы создадите конструктор для Tetris, который принимает Board, создает вокруг него BoardEngine и вызывает конструктор BoardEngine.Тогда вы можете встроить этот конструктор и Пуф!ваша доска исчезает из интерфейса Tetris - и все ваши существующие тесты все еще работают.Насколько я понимаю, это считается рефакторингом, пока зеленый.

2 голосов
/ 26 июля 2010

В целом, если вы измените дизайн, вам также придется изменить свои тесты. В этом случае, поскольку ваш конструктор развивается и принимает новый конкретный тип зависимости, вам нужно будет реорганизовать тесты.

Часть боли здесь в том, что вы берете класс в качестве зависимости; если бы вы брали IBoard, вы могли бы одновременно использовать mocking, как предлагает Синтаксис, и иметь тест, который не зависит от конкретной реализации. Вероятно, вы также могли бы легче реорганизовать свой код, потому что вы могли бы перейти в 2 этапа: добавить контракт интерфейса к новому классу, который вы хотите использовать, и затем постепенно удалить его из старого класса. Вы можете начать этот подход прямо сейчас: сначала извлеките Board в интерфейс, затем внедрите интерфейс в BoardManager и удалите его из Board.

Это, как говорится, иногда, когда вы находитесь на твердой земле, просто проще и быстрее просто сделать несколько тестов красным и собрать их все сразу!

Еще одно замечание: ваша проблема может также указывать на то, что вы не проводите модульное тестирование нужного класса. Если GetColor - это функция, предоставляемая Board или BoardManager, возможно, ваш модульный тест должен выполняться только для этого класса, а класс Tetris должен просто проверить, что для него доступен BoardManager и что он правильно передает ему вызовы. .

0 голосов
/ 26 июля 2010

Из моего pov это не проблема с тестами.

Метод GetColorAt в классе тетриса выглядит как обертка для того же метода в классе платы.Экземпляр класса доски, однако, переместился из класса тетрис в борденджин.Либо выставьте плату из движка как свойство, чтобы класс тетриса имел к нему доступ, либо создайте метод GetColorAt в движке, чтобы связать вызов от тетриса через движок к плате.

Class Tetris{
    Public Color GetColorAt(int x, int y){
        return  _engine.GetColorAt(x,y);
    }
}

Class Boardengine{
    Public Color GetColorAt(int x, int y){
        return  _board.GetColorAt(x,y);
    }
}
0 голосов
/ 26 июля 2010

Похоже, вы должны смотреть на макет рамки для целей тестирования; попробуй мокито - http://mockito.org/

, например

Board board = mock(Board.class);
BoardEngine boardEngine = new BoardEngine(board);
Tetris tetris = new Tetris(boardEngine);
when(board.GetColorAt(0, 0)).thenReturn(Color.RED);
Assert.AreEqual(Color.Red, tetris.GetColorAt(0, 0));

Звучит так, как будто вы пытаетесь поддерживать тесты как проходящие во время рефакторинга (заменяя BoardEngine на Board). Если вы следите за разработкой, управляемой тестами, вам следует обновить тесты, чтобы все тесты не выполнялись; затем обновите ваш код предложенными изменениями.

На практике использование таких структур, как Mockito, позволяет разделить ваши проблемы То есть Вы можете проверить ожидаемое поведение класса Tetris, не делая тест зависимым от поведения классов BoardEngine / Board.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...