Как смоделировать перечисление внутри другого перечисления в Java? - PullRequest
1 голос
/ 21 октября 2019

У меня есть два перечисления:

public enum X {
    INSTANCE;
    private final Y y = Y.INSTANCE;

    public boolean isfunc() {
        return y.someMethod();
    }
}
public enum Y {
    INSTANCE;

    public boolean someMethod() {
        return true;
    }
}

Я написал класс модульного теста для Y путем насмешки с использованием Whitebox. Тем не менее мне нужно получить следующее исключение при написании модульного теста для X:

Я получаю следующее сообщение об ошибке:

Cannot mock/spy class
Mockito cannot mock/spy following:
  - final classes
  - anonymous classes
  - primitive types

Вот примеры модульного теста:

public class XTest {
    @Mock private Y yMock;

    @Before
    public void setUp() throws Exception {
        Whitebox.setInternalState(Y.INSTANCE, "y", yMock);
    }

Я понимаю, что проблема в том, что я пытаюсь высмеивать перечисление, которое является примитивным типом. Я хочу найти способ обойти это.

1 Ответ

1 голос
/ 22 октября 2019

Вот немного из документации Мокито:

39. Mocking финальных типов, перечислений и финальных методов (начиная с 2.1.0)

Mockito теперь предлагает инкубационную, опциональную поддержку для насмешливых финальных классов и методов. Это фантастическое улучшение, которое демонстрирует вечный поиск Mockito для улучшения опыта тестирования. Мы стремимся к тому, чтобы Mockito «просто работал» с финальными классами и методами. Ранее они считались немодными, что не позволяло пользователю издеваться. Мы уже начали обсуждать, как включить эту функцию по умолчанию. В настоящее время эта функция по-прежнему не является обязательной, поскольку мы ожидаем дополнительных отзывов от сообщества.

Эта функция по умолчанию отключена, поскольку она основана на совершенно другом механизме насмешек, который требует большей обратной связи от сообщества.

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

Примерно так:

public class Y {
    private Y() {}
    private final static Y y = new Y();
    public static Y getInstance() {
        return y;
    }

    public boolean someMethod() {
        return true;
    }
}

        enum X {
            INSTANCE;
            private final Y y = Y.getInstance();

            public boolean isfunc() {
                return y.someMethod();
            }
        }

        public class XTest {
            @Mock private Y yMock;

            @Before
            public void setUp() throws Exception {
                Whitebox.setInternalState(X.INSTANCE, "y", yMock);
            }

            @Test
            void test() {  // ...
            }
        }

Я бы добавил, что мне не нравится использовать Whitebox во время тестов. Я считаю, что все, что может сделать тест, мой код должен уметь делать, так как тест является первым реальным клиентом моего модуля и индикатором того, что могут захотеть делать будущие клиенты. Например, так же, как тест хотел бы заменить Y на фиктивный Y, в будущем кто-то может захотеть использовать X с другим производственным Y.

Я бы изменил Y, чтобы использовать интерфейс, и удалил быfinal для переменной y в X, чтобы сделать ее настраиваемой, следующим образом:

interface IY
{
    public boolean someMethod();
}

public class Y implements IY {
    private Y() {}
    private final static IY y = new Y();
    public static IY getInstance() {
        return y;
    }

    public boolean someMethod() {
        return true;
    }
}    

        enum X {
            INSTANCE;
            private IY y = Y.getInstance();
            public void setY(IY y)
            {
                this.y = y;
            }

            public boolean isfunc() {
                return y.someMethod();
            }
        }

        public class XTest {
            @Mock private Y yMock;

            @Before
            public void setUp() throws Exception {
                X.INSTANCE.setY(yMock);
            }

            @Test
            void test() { // ...
            }
        }

Я бы пожертвовал некоторой безопасностью (например, возможностью X.INSTANCE.setY (null);) для конфигурируемостии чистый код.

...