У меня есть класс под названием ConfigReferenceProcessor
, который отвечает за создание экземпляров новых объектов данного типа и их настройку с использованием предоставленной информации о конфигурации. Тип объекта, который создается, должен основываться на абстрактном базовом классе, который называется BaseConfigurable
(В этом базовом классе есть методы, которые мне нужно вызвать для настройки нового экземпляра). Заметка в будущем: BaseConfigurable
не в порядке, поэтому я не могу внести никаких изменений в ее код.Мощный новый экземпляр, созданный путем отражения с использованием PowerMockito
Я пытаюсь модульным тестированием методы processConfigReference
, который делает следующее:
public <T extends BaseConfigurable> T processConfigReference(
Class<T> clazz, ConfigReferenceCfg configRef) {
// All this in a try/catch
Class<? extends T> objClass = Class.forName(configRef.getClassName())
.asSubclass(clazz);
Constructor<? extends T> constructor = objClass.getConstructor();
T obj = constructor.newInstance();
// Some methods to setup and configure the new instance, including:
obj.loadConfig(configRef.getConfigName());
return obj;
}
В моем тестовом модуле, мне нужно контролировать метод loadConfig
, потому что я не хочу, чтобы перетащить в все поведение конфигурации с файловой системой поиска в т.д. Моя первая мысль была просто создать свой собственный макет объекта:
static class MockConfigurable extends BaseConfigurable {
@Override
public void loadConfig(String configName) {
// Do nothing.
}
// Mandatory methods
}
к сожалению, я не могу переопределить loadConfig
клюв ause объявлен как final
в базовом классе.
я нашел другие вопросы на переполнении стека о насмешливом создании объекта с использованием метода PowerMockito whenNew
и попытался использовать это, чтобы создать свой макет, насмехаясь над окончательным методом, а также возвращение фиктивного объекта, когда создаются новые экземпляры:
@RunWith(PowerMockRunner.class)
@PrepareForTest({ TestConfigReferenceProcessor.MockConfigurable.class, ConfigReferenceProcessor.class })
public class TestConfigReferenceProcessor {
static class MockConfigurable extends BaseConfigurable {
// Mandatory methods
}
@Mock private MockConfigurable mockConfigurable;
@Before
public void initializeMockConfigurableInstance() throws Exception {
doNothing().when(mockConfigurable).loadConfig(any(String.class));
whenNew(MockConfigurable.class).withAnyArguments().thenReturn(mockConfigurable);
}
@Test
public void shouldProcessConfigRef() {
MockConfigurable result =
ConfigReferenceProcessor.forClass(MockConfigurable.class)
.processConfigReference(configRefCfg);
// Fails!
verify(mockConfigurable).loadConfig(any(String.class));
}
}
Но этот подход, похоже, не работает для меня. Я подозреваю, что это не работает, потому что я фактически не создаю объект, используя new
.
Есть ли другой способ обойти эту проблему?
Вы правы, сомневаетесь, что можете переопределить или издеваться над базовыми материалами отражения Java, такими как 'constructor.newInstance()', но возможно, что-то еще можно сделать раньше. Можете ли вы дать больше информации о том, как «конструктор» входит в картину? Может быть, мы могли бы что-то там сделать. – jhericks
@jhericks Я отредактирую сообщение, чтобы включить более подробную информацию о части отражения, но эффективно, я использую 'Class.forName' для загрузки класса. Точный класс, который мне нужно загрузить, указан в аргументе 'configRef', поэтому класс, который я передаю, просто используется для проверки того, что класс, который я загружаю, является подклассом (у меня есть много разных подсемейств классов, все из которых производятся от' BaseConfigurable'). –