Как работают фреймворки Java Mocking? - PullRequest
23 голосов
/ 08 июня 2010

Это НЕ вопрос о том, какая платформа является лучшей и т. Д.

Я никогда не использовал фальшивые рамки, и я немного озадачен идеейКак он знает, как создать фиктивный объект?Это делается во время выполнения или генерирует файл?Откуда ты знаешь его поведение?И самое главное - каков рабочий процесс использования такой инфраструктуры (каков пошаговый порядок создания теста)?

Кто-нибудь может объяснить?Вы можете выбрать любой понравившийся фреймворк, например, просто скажите, что это такое.

Ответы [ 5 ]

15 голосов
/ 08 июня 2010

Конструктор для проверки подлинности выводит избыточность и шаблон из теста на проверку.

Он знает, как создать объект Mock, потому что вы, конечно, говорите об этом (если только вы не имели в виду что-то еще с этим вопросом).

«Стандартный» способ создания фиктивного объекта - это использование / злоупотребление классом java.lang.reflect.Proxy для создания реализации интерфейса во время выполнения. Это делается во время выполнения. Прокси имеет ограничение в том, что он не может прокси конкретных классов. Для выполнения моделирования конкретных классов требуется динамическое создание байт-кода, которое создает подклассы, которые переопределяют реальную реализацию открытых методов, по существу, с тем, что было бы сделано с прокси-сервером (запишите параметры метода и верните предварительно определенное значение). Это имеет ограничение в том, что он не может создавать подклассы конечных классов. Для этого у вас есть такие решения, как JDave , которые (я полагаю, я не подтвердил это) смешивают с загрузчиком классов, чтобы удалить окончательное обозначение класса перед его загрузкой, поэтому класс не находится в окончательный факт во время выполнения, если речь идет о JVM.

Инфраструктура Mocking в основном сводится к захвату параметров и проверке их на соответствие заранее определенным ожиданиям, а затем возвращает предварительно сконфигурированное или разумное значение по умолчанию. Он не ведет себя каким-либо особым образом, и в этом суть. Вызывающий код проверяется, что он вызывает метод с правильным параметром и, возможно, как он реагирует на конкретные возвращаемые значения или выданные исключения. Никаких побочных эффектов или реальных достижений при вызове реального объекта не происходит.

Вот реальный пример из проекта, использующего JMock с JUnit4. Я добавил комментарии, чтобы объяснить, что происходит.

 @RunWith(JMock.class) //The JMock Runner automatically checks that the expectations of the mock were actually run at the end of the test so that you don't have to do it with a line of code in every test.
public class SecuredPresentationMapTest {

private Mockery context = new JUnit4Mockery(); //A Mockery holds the state about all of the Mocks. The JUnit4Mockery ensures that a failed mock throws the same Error as any other JUnit failure.

@Test
public void testBasicMap() {
    final IPermissionsLookup lookup = context.mock(IPermissionsLookup.class); //Creating a mock for the interface IPermissionsLookup.
    context.checking(new Expectations(){{ //JMock uses some innovative but weird double brace initialization as its standard idom.
        oneOf(lookup).canRead(SecuredEntity.ACCOUNTING_CONTRACT);
            //expect exactly one call to the IPermissionsLookup.canRead method with the the enum of ACCOUNTING_CONTRACT as the value. Failure to call the method at all causes the test to fail.
            will(returnValue(true)); //when the previous method is called correctly, return true;
    }});

    Map<String, Component> map = new SecuredPresentationMap(lookup, SecuredEntity.ACCOUNTING_CONTRACT);
    //This creates the real object under test, but passes a mock lookup rather than the real implementation.
    JLabel value = new JLabel();
    map.put("", value);
    assertThat(((JLabel) map.get("")), is(value)); //This ensures that the Map returns the value placed, which it should based on the fact that the mock returned true to the security check.
  }
}

Если передаваемая имитация была проигнорирована, тест не прошел бы. Если карта не может вернуть значение, помещенное в нее, тест не пройден (это стандартный JUnit).

Что проверяется здесь и в другом противоположном тесте, так это то, что в зависимости от того, что интерфейс IPermissionsLookup говорит о безопасности, карта меняет свое поведение относительно того, что возвращается. Это базовый хороший случай. Другой тест, макет возвращает false, и что-то еще ожидается от карты. Использование макета гарантирует, что карта использует метод IPermissionsLookup для определения состояния безопасности и того, что возвращается.

9 голосов
/ 08 июня 2010

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

Как он знает, как создать макет объекта?

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

Это делается во время выполнения или генерирует файл

jMock создает его во время выполнения.

Откуда вы знаете его поведение?

Ложные объекты довольно тупые. Вы указываете поведение, которое вы ожидаете от них.

И самое главное - что это рабочий процесс использования такой основы (что является пошаговым для создания тест).

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

jmock делает это, вводя специальный тестовый прогон, который проверяет все ожидания на все объявленные фиктивные объекты после завершения теста. Если что-то не совпадает, генерируется исключение.

Обычно шаблон выглядит так:

  1. Приобретение фиктивной фабрики (называемой Mockery in jmock) из воздуха (с помощью специального конструктора без аргументов).
  2. Создание необходимых макетов объектов.
  3. Настройка ожидания для фиктивных объектов
  4. Вызовите метод, который вы тестируете, передавая макеты вместо реальных объектов
  5. Если ваш метод возвращает некоторые значения, проверьте ожидаемое значение с помощью обычных assertXXX методов.
5 голосов
/ 08 июня 2010

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

1 голос
/ 08 июня 2010

Я думаю, что Документация EasyMock - это способ начать работу. В нем много примеров, которые легко понять.

0 голосов
/ 08 июня 2010

EasyMock (http://easymock.org/) - это библиотека макетов, которую я использовал чаще всего. (Есть и другие: jMock, Mockito и т. Д.)

Большинство из них создают объект во время выполнения, которыеВы можете управлять. Основной поток:

  1. Создание макета
  2. Укажите, как он должен действовать, сообщая макету фреймворка, что требует ожидания. (Это зависит от фреймворка.)
  3. Используйте макет в своем тесте, как если бы он был реальным
  4. Некоторые платформы позволяют (или требуют), чтобы вы "проверяли", что макет использовался правильно.
...