подавить одноэлементный конструктор в java с помощью powermock

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

Насколько я понимаю, способ решения этой проблемы будет примерно таким:

public class MySingleton extends AbstractSingletonParent {
    public final static MySingleton Only = new MySingleton();
    private MySingleton(){
        super(someVar); // I want the super-class constructor to not be called
        //
        //more code I want to avoid
    }

    public Object stubbedMethod() {}
}

public class ClassToBeTested {
    public void SomeMethod(){
        Object o = MySingleton.Only.stubbedMethod();
    }
}


@RunWith(PowerMockRunner.class)
@PrepareForTest(MySingleton.class)
public class TestClass {
    @Test
    public void SomeTest() {
        suppress(constructor(MySingleton.class));
        mockStatic(MySingleton.class);

        PowerMock.replay(MySingleton.class);
        // invoke ClassToBeTested, etc

        PowerMock.verify(MySingleton.class);

        //make some assertions
    }
}

К сожалению, во время вызова createMock происходит срабатывание конструктора MySingleton, но он по-прежнему вызывает суперконструктор.

Я делаю что-нибудь глупое? Я нашел в Интернете пример, делающий почти именно это, но с использованием устаревшего метода suppressConstructor. Несмотря на устаревание, я пробовал и это, но безрезультатно ...

Возможно ли то, что я пытаюсь сделать? Если да, то что я делаю не так?

* Отредактированная версия теперь работает.


person Chad Blomquist    schedule 11.11.2011    source источник


Ответы (3)


Вам нужно аннотировать TestClass аннотацией @PrepareForTest, чтобы у него была возможность манипулировать байт-кодом синглтонов.

Кроме того, сигнатура подавления суперкласса ctor должна включать класс somevar; прямо сейчас вы просто подавляете ctor по умолчанию.

См. @PrepareForTest Документы по API. Вот запись в блоге с некоторыми подробностями.

FWIW, у меня работает:

@RunWith(PowerMockRunner.class)
@PrepareForTest({EvilBase.class, NicerSingleton.class})
public class TestEvil {

    @Test
    public void testEvil() {
        suppress(constructor(EvilBase.class));
        assertEquals(69, EvilBase.getInstance().theMethod());
    }

    @Test public void testNice() {
        suppress(constructor(EvilBase.class));
        suppress(constructor(NicerSingleton.class));
        assertEquals(42, NicerSingleton.getInstance().theMethod());
    }

}
person Dave Newton    schedule 11.11.2011
comment
Эта аннотация ничего не изменила. Я пробовал использовать ClassToBeTested.class и MySingleton.class, ни один из которых, похоже, никоим образом не изменил результат. - person Chad Blomquist; 12.11.2011
comment
@ user1042480 Какая версия PowerMock? - person Dave Newton; 12.11.2011
comment
Использование powermock-easymock-1.4.10-full с easymock-3.1. Java 1.6 - person Chad Blomquist; 12.11.2011
comment
Я немного изменил метод тестирования, и это в сочетании с предложенными вами аннотациями, похоже, помогло. Аннотации определенно были частью проблемы, поэтому спасибо за помощь! - person Chad Blomquist; 12.11.2011
comment
@ user1042480 Кстати, я не уверен, что вам нужно подавлять оба ctors; Я думаю, что если вы подавите ctor суперкласса, база не будет вызвана. - person Dave Newton; 12.11.2011
comment
не можете найти метод constructor, не могли бы вы добавить в пример необходимый импорт? - person Eduardo; 20.07.2017
comment
@Eduardo Я понятия не имею, что это будет дальше - я уверен, что за последние шесть лет все изменилось. - person Dave Newton; 20.07.2017

Как насчет того, чтобы вы установили поле экземпляра ('only' в вашем коде) вашего синглтона с экземпляром, созданным с помощью конструктора, который вы хотите (вы можете сделать все это с помощью Reflection API или dp4j).

В качестве мотивирующего примера публикации dnvlLTg1OTgtN2Zm&hl=ru"> dnvlLTg1OTgtN2Zm&hlMDdm>

person simpatico    schedule 17.11.2011

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

Чтобы сделать ваш код тестируемым, используйте DI. С помощью DI вы передаете одноэлементный класс в качестве аргумента конструктора в свой тестовый класс. И теперь, когда вы передаете аргумент, внутри своего тестового примера вы можете создать собственную реализацию класса AbstractSingleton, и ваш тестовый пример должен работать нормально.

С DI ваш код станет более тестируемым.

person Ravi Bhatt    schedule 11.11.2011
comment
Спасибо за совет, но это не вариант. - person Chad Blomquist; 12.11.2011