Сброс статических полей для тестов JUnit

У меня есть набор тестов JUnit, которые вызывают основной метод в Java-программе, проходят в args и проверяют вывод. Все нормально.

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

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

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

Edit-обратите внимание, что у меня нет контроля над кодом, который тестируют модульные тесты - я не могу изменить их имена полей, и, к сожалению, я также не буду знать их имена полей. Я думаю, что это делает это невозможным без начать новый процесс?

3 ответов


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

сказав это, вы можете найти библиотека BeanInject полезная. Вы могли бы поставить @After аннотированный метод в ваш тестовый класс и сбросить статические поля с помощью инъекции:

Inject.field("thatStaticField").of(thatObjectWithStaticFields).with("default value");

таким образом, вам нужно только знать поле имена, но вам не обязательно иметь возможность изменять класс с помощью полей. Библиотека делает это с помощью отражения.

кроме того, мне пришло в голову, что если вы тестируете что-то, содержащее части, которые вы не можете контролировать, почему бы вам не попытаться высмеять эти части, скажем, Mockito?

ИЗМЕНИТЬ/ДОБАВИТЬ: OK, поэтому ваша проблема заключается в том, что вы даже не знаете начальных значений возможных статических переменных, которые могут иметь или не иметь классы. Я вижу два возможные подходы: 1) вам нужно будет либо сохранить их значения при первой загрузке класса и сбросить значения между каждым тестом, либо 2) вы должны получить совершенно новый экземпляр класса из загрузчика классов.

В пункте 1), вам нужно будет использовать отражение, чтобы перебирать все поля в вашем методе @BeforeClass, сохранять их начальные значения в некоторые Map<String,Object> structure, а затем сбросьте значения в методе @Before или @After. Вот некоторые темы о циклических через поля класса, используя отражение:цикл по всем полям в классе Java

Что касается пункта 2), у вас есть инструкции для этого (с участием загрузчиков классов) здесь:Java: как "перезапустить" статический класс?

Это довольно круто, что вы можете сделать с отражением и тому подобное. :)


вы должны явно инициализировать любое статическое состояние в своих тестовых классах, обычно это делается в аннотированных методах @Before или @BeforeClass

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


взгляните на этот пост: Установить Частное Статическое Поле. В отличие от BeanInject или ReflectionTestUtils (который я использую много), этот механизм не требует экземпляра класса. Поскольку это статическое поле, я не был уверен,есть ли у вас экземпляр. Если да, используйте один из двух вышеперечисленных.

скопировал из поста:

 public static void main(String[] args) throws Exception
{
    Field field = MyClass.class.getDeclaredField("woot");
    field.setAccessible(true);
    field.set(null, "New value");
}

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

как заявили другие, сделайте это в @Before метод для обеспечения состояния до начала теста. Делать это в @After подвержен ошибкам, поскольку предполагается, что другой тест может повлиять на состояние статического поля.