Разрешение дубликата тестовой идиомы в JUnit - PullRequest
2 голосов
/ 03 ноября 2011

У меня есть 2 случая, которые кажутся мне одной и той же проблемой, хотя они совершенно разные:

1) Я проверяю как чтение, так и запись объекта в базу данных.Поскольку я очищаю и перестраиваю объект каждый раз, тест записи должен читать, чтобы подтвердить запись каждого поля, и тест чтения записывается первым, поэтому тесты выглядят одинаково.Однако я не хочу оставлять основной метод в интерфейсе непроверенным.

2) В гораздо меньшем случае я тестирую метод copy () и метод equals () для небольшого объекта данных.,Метод copy () использует equals () для проверки самого себя, а метод equals () проверяет копию.Опять же, тесты дублируются.

Мне кажется, что я что-то здесь упускаю, какой-то способ отделить зависимость, не создавая много дополнительной работы (например, иметь необработанную запись JDBC в базу данных и т. Д.)существует ли стандартный способ борьбы с такого рода дублированием тестов?

Ответы [ 2 ]

1 голос
/ 03 ноября 2011

Для меня этот вид теста - это запах кода.Вопрос всегда в том, что точно этот тест проверяет?В этом тесте, чему вы доверяете и чему не доверяете?

Для меня вы не можете доверять read () и write () вместе, они, вероятно, находятся в одном классе, написанномтот же человек.Так что, если вы тестируете read () с помощью вызова write (), тогда это не очень хороший тест, вы тестируете, что write () и read () синхронизированы, а не то, что они должны делать.

Во втором примере вы проверяете, что копирование и равенство синхронизированы, та же проблема.

Допустим, это была реализация уровня персистентности:

public class PersistenceLayer {
    private Object object;

    void write(Object object) {
        this.object = object;
    }

    Object read(Long id) {
        return object;
    }
}

Вопрос в том, пройдут ли ваши тесты с этим постоянным слоем?Но он явно не делает то, что вы хотите.Это не идет рядом с базой данных.Аналогичным образом, пройдут ли ваши тесты, если ваши операции чтения и записи будут разделять сеанс / транзакцию?В этом случае данные никогда не будут фактически переданы в базу данных.Это может сделать откат в конце.Но ваши тесты все равно пройдут.

Читая ваше описание, вы проверяете, что когда я вызываю write () и затем read (), я получаю похожий объект обратно.То, что я ожидал бы от метода write (), это то, что он записывает данные в базу данных.Поэтому, если я проверяю , что , мне нужно это проверить.Поэтому у меня должен быть другой канал, который я могу использовать для проверки чтения и записи.Обычно это заканчивается созданием нового Соединения через JDBC и выполнением выбора.

Таким образом, мой код тестирования будет

testWrite() {
    write(o);
    Object o2 = readByJdbc("SELECT * FROM table WHERE id = ?", o);
    assertObjectsEqual(o, o2); // this needs to compare all values
}

testRead() {
    write(o);
    Object o2 = read(o.id);
    Object o3 = readByJdbc("SELECT * FROM table WHERE id = ?", o);

    assertObjectsEqual(o2, o3); // this needs to compare all values
}

testWrite () записывает в базу данных и гарантирует, что данныезаписывается в базу данных путем открытия соединения JDBC и чтения таким образом (другой сеанс, другая транзакция, т.е. данные будут в базе данных).

testRead () записывает в базу данных и сравнивает два объекта, возвращенныечитать через слой постоянства и через JDBC.Я дублирую вызов write (o), но это приемлемо, потому что мы знаем, сработает ли write при вызове другого теста.Я мог бы написать другой writeByJdbc, но все, что я получил бы, это то, что один тест провалится вместо двух.

Фактически, в зависимости от вашего уровня паранойи, вам не нужно сравнивать все значения в assertObjectsEqual ().Если вы, например, используете hibernate, вы можете просто предположить, что все объявлено правильно, и проверить наличие строки в базе данных.Я делаю это часто, потому что я верю в спящий режим.Но в этом случае мне нужно проверить, как я называю hibernate, как определяются объекты.

Код jdbc не должен быть длинным и сложным, для простого выбора я просто создаю списокОтображение столбцов в значения:

private List<Map<String, Object>> resultSetToListMap(ResultSet resultSet) throws SQLException {
    int columnCount = resultSet.getMetaData().getColumnCount();
    List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();

    while (resultSet.next()) {
        Map<String, Object> map = new LinkedHashMap<String, Object>();

        for (int i = 1; i <= columnCount; i++) {
            map.put(resultSet.getMetaData().getColumnName(i), resultSet.getObject(i));
        }

        list.add(map);
    }

    return list;
}

Этого более чем достаточно для большинства тестов.

1 голос
/ 03 ноября 2011

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

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