У меня был тот же вопрос, и это действительно запутанно, вы должны учитывать, что переопределение и новые ключевые слова работают только с объектами базового класса типа и значением производного класса. В этом случае вы увидите эффект переопределения и новый: Итак, если у вас есть class A
и B
, B
наследуется от A
, вы создаете экземпляр объекта следующим образом:
A a = new B();
Теперь при вызове методы учитывают его состояние. Override: означает, что он расширяет функцию метода, а затем использует метод в производном классе, тогда как новый сообщает компилятору, чтобы скрыть метод в производном классе и вместо этого использовать метод в базовом классе. Вот очень хороший взгляд на эту тему:
Вместо этого вы можете написать следующее:
$qry = "SELECT * FROM mytable where userid='";
$qry.= mysql_real_escape_string($_GET['userid'])."' AND category='";
$qry.= mysql_real_escape_string($_GET['category'])."' ORDER BY id DESC";
Но использовать подготовленные операторы лучше использовать универсальную библиотеку,
PowerMock - это фреймворк, расширяющий другие фиктивные библиотеки, такие как EasyMock, более мощными возможностями. PowerMock использует настраиваемый загрузчик классов и манипуляции с байт-кодом для имитации статических методов, конструкторов, конечных классов и методов, частных методов, удаления статических инициализаторов и т. Д.
Вот пример теста, имитирующий статический конечный метод в этом примере показано, как имитировать и некоторые другие типы:
@Test
public void testMockStaticFinal() throws Exception {
mockStatic(StaticService.class);
String expected = "Hello altered World";
expect(StaticService.sayFinal("hello")).andReturn("Hello altered World");
replay(StaticService.class);
String actual = StaticService.sayFinal("hello");
verify(StaticService.class);
assertEquals("Expected and actual did not match", expected, actual);
// Singleton still be mocked by now.
try {
StaticService.sayFinal("world");
fail("Should throw AssertionError!");
} catch (AssertionError e) {
assertEquals("\n Unexpected method call sayFinal(\"world\"):",
e.getMessage());
}
}
JMockit позволяет вам высмеивать статические методы и конечные классы. Я предполагаю, что он использует некоторый classloadin-fu, хотя я действительно не изучал это.
JMockit Expectations API позволяет устанавливать ожидания для любого вида вызова метода (для интерфейсов, абстрактных классов, конкретных конечных или не конечных классов и для статических методов), а также для создания экземпляров классов с помощью любых конструкторов.
Как уже отмечалось, можно использовать JMockit . Пример:
@Test
public void mockStaticAndFinalMethods(@Mocked LegacyService mock) {
new Expectations() {{
LegacyService.staticMethod("hello"); result = "Hello altered World";
}};
String actual = LegacyService.staticMethod("hello");
new LegacyService().finalMethod(123, "test");
assertEquals("Hello altered World", actual);
new Verifications() {{
mock.finalMethod(123, "test"); // verify this call occurred at least once
}};
}
Если ваш метод, не подлежащий рефакторингу, использует что-то вроде JNDI для подключения к другой службе, я бы подумал о запуске службы JDNI и заполнении ее заглушками, которые вы контролируете. Это больно, но относительно просто. Это может означать настройку базы данных или прослушивателя JMS или чего-то еще, но должна быть облегченная реализация java, которую вы можете добавить в тесты.
JMock вместе с JDave может имитировать финальные методы и классы, если вам это нужно. Здесь инструкции. При этом я бы рассматривал этот устаревший код (как уже предлагали другие) как внешнюю зависимость, создавал интерфейсы и издевался над ними. Это еще один уровень косвенного обращения, но, поскольку вы не можете изменить устаревший код, он кажется разумным.
Как насчет уровня косвенного обращения / внедрения зависимостей?
Поскольку унаследованный служебный проект является вашей зависимостью, создайте интерфейс, чтобы отделить его от вашего кода. Теперь ваша реальная / производственная реализация этого интерфейса делегирует устаревшие служебные методы.
public LegacyActions : ILegacyActions
{
public void SomeMethod() { // delegates to final/static legacy utility method }
}
Для своих тестов вы можете создать имитацию этого интерфейса и избежать взаимодействия с устаревшей утилитой.