Сброс статических полей для тестов 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
подвержен ошибкам, поскольку предполагается, что другой тест может повлиять на состояние статического поля.