Как вы тестируете / изменяете непроверенный и непроверяемый код? - PullRequest
9 голосов
/ 10 августа 2008

В последнее время мне пришлось изменить код на старых системах, где не весь код имеет модульные тесты.
Прежде чем вносить изменения, я хочу написать тесты, но каждый класс создал множество зависимостей и других анти-шаблонов, что усложнило тестирование.
Очевидно, я хотел реорганизовать код, чтобы его было проще тестировать, писать тесты и затем изменять его.
Это так, как ты это сделаешь? Или вы потратили бы много времени на написание трудных для записи тестов, которые в основном будут удалены после завершения рефакторинга?

Ответы [ 4 ]

6 голосов
/ 10 августа 2008

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

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

public class MyClass {
    public MyClass() {
        // undesirable DB logic
    }
}

становится

public class MyClass {
    public MyClass() {
        loadFromDB();
    }

    protected void loadFromDB() {
        // undesirable DB logic
    }
}

и тогда ваш тест выглядит примерно так:

public class MyClassTest {
    public void testSomething() {
        MyClass myClass = new MyClassWrapper();
        // test it
    }

    private static class MyClassWrapper extends MyClass {
        @Override
        protected void loadFromDB() {
            // some mock logic
        }
    }
}

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

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

Это что-то вроде хака, но я нашел это весьма полезным.

3 голосов
/ 11 августа 2008

@ Валтерсом

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

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

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

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

Я твердо верю, что провальный тест должен быть исправлен как можно скорее, как если бы вы исправляли код, который не компилируется как можно скорее.

0 голосов
/ 30 августа 2008

Я прочитал «Эффективная работа с устаревшим кодом», и я согласен, что это очень полезно для работы с «непроверяемым» кодом.

Некоторые методы применимы только к скомпилированным языкам (я работаю над «старыми» приложениями PHP), но я бы сказал, что большая часть книги применима к любому языку.

Рефакторинг книг иногда предполагает, что код находится в полуидеальном состоянии или в состоянии «обслуживания» перед рефакторингом, но системы, над которыми я работаю, не идеальны и были разработаны как приложения «учись по ходу» или как первые приложения для Используются некоторые технологии (и я не виню в этом первоначальных разработчиков, поскольку я один из них), поэтому тестов вообще нет, а код иногда грязный. Эта книга посвящена такой ситуации, в то время как другие книги по рефакторингу обычно не (ну, не до такой степени).

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

0 голосов
/ 11 августа 2008

Я не уверен, почему вы говорите, что модульные тесты будут удалены после завершения рефакторинга. На самом деле ваш пакет юнит-тестов должен запускаться после основной сборки (вы можете создать отдельную сборку «тестов», которая просто запускает юнит-тесты после сборки основного продукта). Тогда вы сразу увидите, не нарушат ли изменения в одной части тесты в другой подсистеме. Обратите внимание, что это немного отличается от запуска тестов во время сборки (как некоторые могут рекомендовать) - некоторые ограниченные тесты полезны во время сборки, но, как правило, непродуктивно «сбивать» сборку только потому, что какой-то модульный тест оказывается неудачным.

Если вы пишете Java (скорее всего), посмотрите http://www.easymock.org/ - может быть полезно для уменьшения сцепления в тестовых целях.

...