Пересмешивание внутреннего экземпляра объекта - PullRequest
7 голосов
/ 15 декабря 2011

Я пишу тестовый класс для тестирования моего класса ImporterService. Этот сервис читает InputStream и создает Объект из его данных. Объект, в данном случае класс Builder, создается в классе ImporterService. Чтобы протестировать мой класс ImporterService, мне нужно проверить вызовы класса Builder. Для этого я хочу использовать Mocking framework, однако как можно создать фиктивный экземпляр объекта «Builder» вне «ImporterService»?

Метод моего класса ImporterService выглядит следующим образом:



    public Builder importFrom(BufferedReader reader) throws IOException {
        String someValue = readFrom(reader);
        Builder builder = new Builder();   // I need to mock this Builder object...
        builder.someMethod(someValue);     // to see of a method is called with the expected value
    }

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

Ответы [ 5 ]

2 голосов
/ 15 декабря 2011

Если вы используете любую библиотеку внедрения зависимостей (например, Spring), вы можете внедрить фиктивный объект вместо компоновщика в класс ImporterService. Или вы можете заменить вызов конструктора вызовом factory и использовать factory, который возвращает макеты в тестовом коде.

1 голос
/ 15 декабря 2011

Да, вы можете сделать то, что вы предложили, или:

Создать класс Factory, в котором вы создаете Builder объекты, и назначить его классу чтения.В своих модульных тестах смоделируйте эту фабрику и заставьте ее построить Builder по вашему выбору, чтобы вы могли проверять вызовы методов в своем модульном тесте.

Вот пример использования EasyMock , показывающий, как этого можно достичь:

public class Reader{
   private BuilderFactory factory = new BuilderFactory(); // Use production factory by default
   public Builder importFrom(BufferedReader reader) throws IOException {
        String someValue = readFrom(reader);
        Builder builder = factory.buildBuilder();
        builder.someMethod(someValue);     // to see of a method is called with the expected value
    }
}

В своих модульных тестах вы делаете следующее:

Reader classUnderTest = new Reader();
BuilderFactory fakeFactory = EasyMock.createNiceMock(BuilderFactory.class);
Builder builder = EasyMock.createMock(Builder.class);
EasyMock.expect(fakeFactory.buildBuilder()).andReturn(builder);
builder.someMethod("value here");
EasyMock.expectLastCall().once();
EasyMock.replay(fakeFactory, builder);
classUnderTest.importFrom(bufferReader);
// Very that all calls were correctly performed on the builder
EasyMock.verify(builder);
0 голосов
/ 15 декабря 2011

вы можете изменить подпись функции на что-то вроде этого:

public Builder importFrom(BufferedReader reader, Builder builder) throws IOException {

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

Идея внедрения зависимости заключается в том, чтобы запросить все ваши зависимости, и если класс / функция делает это, код становится очень тестируемым.

0 голосов
/ 15 декабря 2011

Некоторые фальшивые фреймворки, такие как PowerMock , могут имитировать конструирование объектов.

0 голосов
/ 15 декабря 2011

Предполагая, что вы используете jMockt (я рекомендую этот макет), вы сможете сделать следующее:

  @Test
    public void testFoo(@Mocked Builder builder) {
        new Expectations() {
            {
                new Builder();
                returns(builder);

                builder.setSomemethod()
                ...
            }
        };

        assertSame(builder,impoertesService.importFrom(...));
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...