UnfinishedStubbingException при выполнении заглушки из класса, отличного от тестового класса - PullRequest
2 голосов
/ 24 октября 2019

Я использую PowerMock для насмешки java.net.Inet4Address (помимо прочего), чтобы вернуть определенный IP-адрес (getHostAddress()), а также проверить, является ли он закольцованным (isLoopbackAddress()). Я обнаружил, что если я выполняю фактическую заглушку (PowerMock.doReturn(...).when(mock).methodToStub()) где-либо, кроме как внутри тестового класса или непосредственно внутреннего класса, я получаю исключение UnfinishedStubbingException.

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

Ниже приведен код, демонстрирующий проблему.

TestClass.java

/* package, imports... */

@RunWith(PowerMockRunner.class)
@PrepareForTest({Inet4Address.class})
public class TestClass {

    @Test
    public void test() {
        Inet4Address mocked = PowerMockito.mock(Inet4Address.class);

        // Option 1: Do it from within this class - WORKS
        doStubbing(mocked);

        // Option 2: Do it from an inner class - WORKS
        Inner.doStubbing(mocked);

        // Option 3: Do it from an inner class of the inner class - FAILS
        Inner.Deeper.doStubbing(mocked);

        // Option 4: Do it from an entirely different class - FAILS
        OtherClass.doStubbing(mocked);
    }

    private void doStubbing(Inet4Address mocked) {
        PowerMockito.doReturn(true).when(mocked).isLoopbackAddress();
        PowerMockito.doReturn("127.0.0.1").when(mocked).getHostAddress();
    }

    public static class Inner {

        static void doStubbing(Inet4Address mocked) {
            PowerMockito.doReturn(true).when(mocked).isLoopbackAddress();
            PowerMockito.doReturn("127.0.0.1").when(mocked).getHostAddress();
        }

        public static class Deeper {

            static void doStubbing(Inet4Address mocked) {
                PowerMockito.doReturn(true).when(mocked).isLoopbackAddress();
                PowerMockito.doReturn("127.0.0.1").when(mocked).getHostAddress();
            }

        }

    }

}

OtherClass.java

/* package, imports... */

public class OtherClass {

    public static void doStubbing(Inet4Address mocked) {
        PowerMockito.doReturn(true).when(mocked).isLoopbackAddress();
        PowerMockito.doReturn("127.0.0.1").when(mocked).getHostAddress();
    }

}

Я поместил создание макета в начале, общий для всех сценариев. Не имеет значения, создается ли макет из того же класса, где выполняется заглушка. Я также сделал методы статичными для удобства чтения;Поведение остается прежним, если сначала создаются экземпляры классов.

Я знаю, что есть обходные пути, чтобы я мог заставить свой тест работать (выполните макетирование прямо в классе теста, смоделируйте интерфейс InetAddress вместо реализации IPv4и т. д.), но я хотел бы знать, почему PowerMock ведет себя так. Я мог бы почти понять это, если бы он работал только внутри тестового класса, но почему он работает и во внутреннем классе?

...