Сделать и ссылаться на объект-заглушку для тестирования, не нуждаясь в классе, который расширит заглушку

1

Это, наверное, простой вопрос, но я не смог его укоротить.

Я тестирую мой класс ClassToTest. В процессе производства он будет выполнять операции над сторонним библиотечным объектом, экземпляром ThirdPartyClass.

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

Проблема в:

  • ClassToTest имеет метод setThirdPartyClass(ThirdPartyClass o). Таким образом, чтобы пропустить это, заглушке пришлось бы расширить ThirdPartyClass. Это означает, что мои тесты должны будут использовать стороннюю библиотеку, тогда как мой unit тест должен быть автономным.

Причина в том, что мой код будет запущен во встроенной системе, а соответствующая библиотека в основном выполняет собственный код. Но я хочу разработать и протестировать свой код изолированно на своем ПК. Но я не хочу изменять подписи аргументов ClassUnderTest и т.д., Например, меняя между собой:

classToTest.setThirdPartyClass(ThirdPartyClass o){ /*....*/ }

а также

classToTest.setThirdPartyClass(MyThirdPartyClassStub o){ /*....*/ }

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

Каков хороший способ сделать это?

  • 0
    Можете ли вы привести пример метода, который вы хотите проверить?
  • 1
    Вместо этого используйте Mockito mocks. Он использует генерацию байт-кода для решения этих проблем, и вы получите замену сценария для тестирования.
Теги:
unit-testing
junit
stub

3 ответа

1
Лучший ответ

Возможно, это не лучший пример, но, по существу, использование Mockito для издевательства над ThirdPartyClass.

YourClass для тестирования

public class YourClass {

    private String aString;

    // Method that depends on third party component
    public void someMethod(ThirdPartyClass doc) {
        aString = doc.someStringValue();
    }

    public String getValue() {
        return aString;
    }
}

Протестируйте с помощью Mockito, чтобы высмеивать ThirdPartyClass и контролировать возвращаемое значение

public class YourClassTest {    

    //Class you want to test
    private YourClass testee;

    @Test
    public void testSomeMethod() {

        testee = new YourClass(); 

        //
        // ThirdPartyClass. When the method someStringValue()
        // is called you control the value returned
        //
        ThirdPartyClass testDoc = mock(ThirdPartyClass.class);          
        when(testDoc.someStringValue()).thenReturn("aString");

        // Call method to test and pass mock as argument
        testee.someMethod(testDoc);

        // Check state of your object you want to test
        assertThat(testee.getValue(), equalTo("aString"));      
    }
}
2

Самый простой способ издевательства (ThirdPartyClass) ThirdPartyClass, как уже упоминалось, будет, если этот класс реализует интерфейс, а этот интерфейс - это полный интерфейс, ClassToTest использует ваш ClassToTest. Затем вы можете написать класс MockThirdParty который implements ThirdPartyInterface. Но я думаю, вы не можете этого сделать.

Другой вариант - скрыть ThirdPartyClass за классом ThirdPartyFacade который вы пишете. Когда вы пишете это, вы можете создать ThirdPartyInterface который вы создаете. Методы класса ThirdPartyFacade просто делегируют ThirdPartyClass, поэтому для вас безопасно проводить сравнительно небольшое тестирование этого класса; модульные тесты для этого не нужны. Измените свой ClassToTest чтобы он использовал ссылку на объект ThirdPartyInterface, а не ссылку на объект ThirdPartyClass.

Теперь вы можете написать класс MockThirdPartyFacade для тестирования, который implements ThirdPartyInterface для тестирования ClassToTest. Вы можете сделать этот макет класс простым или сложным, как вам нужно. Различные тестовые примеры могут даже использовать разные классы-макеты; вам не нужен класс общей цели.

1

ThridPartyClass ли ваш ThridPartyClass интерфейс? Если это так, вы можете изменить свой класс под тестом, чтобы использовать интерфейс вместо конкретного класса. Тогда ваш заглушка просто реализует интерфейс.

Если нет, есть издевательские библиотеки, такие как EasyMock и Mockito, которые могут издеваться над классом для вас.

Например, используя easymock:

@Test
public void test(){
   ThirdPartyClass mock = createMock(ThirdPartyClass.class);

   expect(mock.foo().andReturn("bar");
   replay(mock);

   classToTest.setThirdPartyClass(mock);
   //perform your tests on classToTest

}
  • 0
    Спасибо - к сожалению, он не реализует интерфейс; Кроме того, тесты будут проверять результирующее состояние тестируемого объекта вместо вызовов, которые делает объект - я хочу, чтобы тесты были независимы от реализации моего кода. AFAIK, издевательства могут проверять только те звонки, которые делает объект?
  • 0
    Насмешка над сторонним классом позволяет вашему объекту совершать вызовы этого класса, который, как я полагаю, сотрудничает, чтобы изменить состояние объекта, который вы хотите проверить. Вам не нужно проверять вызовы на макет, если вы не заинтересованы в косвенных выходах.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню