2009-04-12 2 views
3

У меня есть класс с методом переадресации foo:Testing конкретный класс третьей стороной с JMock

void foo(Concrete c, String s) { c.bar(s); } 

Я хочу, чтобы проверить, имеет ли foo, на самом деле, вперед. К сожалению, для меня Concrete является классом в сторонней библиотеке и представляет собой конкретный тип, а не интерфейс. Таким образом, я должен использовать ClassImposteriser в JMock издеваться Concrete, так что в моем тестовом случае, я делаю это:

@Test 
public final void testFoo() { 
    Mockery context = new JUnit4Mockery() {{ 
     setImposteriser(ClassImposteriser.INSTANCE); 
    }}; 

    final Concrete c = context.mock(Concrete.class); 
    final String s = "xxx" ; 

    // expectations 
    context.checking(new Expectations() {{ 

    oneOf (c).bar(s); // exception gets thrown from here 
    }}); 


    new ClassUnderTest.foo(c, s); 
    context.assertIsSatisfied(); 

}

К сожалению, Concrete.bar в свою очередь, вызывает метод, который бросает. Этот метод является окончательным, поэтому я не могу его переопределить. Кроме того, даже если я прокомментирую строку new ClassUnderTest.foo(c, s);, исключение вызывается, когда JMock устанавливает исключения, а не когда вызывается foo.

Итак, как я могу проверить этот метод ClassUnderTest.foo делает переадресацию на Concrete.bar?

Редактировать:
Да, бар окончательный.

Мое решение, которое является не общим, было использование класса «Тестер» в сторонней библиотеке для правильной настройки Concrete.

ответ

5

Непонятно из текста вопроса, если Concrete.bar() является окончательным или Concrete.somethingElse() является окончательным и вызывается из Concrete.bar().

Если Concrete.bar() не является окончательным, создать рукописную заглушки для бетона, как это:

public class ConcreteStub extends Concrete 
{ 
    public int numCallsToBar = 0; 
    @Override 
    public void bar(String s) { numCallsToBar++; } 
} 

и в тестовом коде:

ConcreteStub c = new ConcreteStub(); 
foo(c,"abc"); 
assertEquals(1,c.numCallsToBar); 

If Бетон. bar() является окончательным, это сложнее, и ответ зависит от сложности Concrete и использования вашего проекта класса Concrete. Если ваше использование Concrete достаточно простое, я бы рассмотрел возможность обертывания Concrete в интерфейсе (Adapter Pattern), который вы можете затем легко выстроить.

Преимущества решения адаптера адаптера: возможно, уточнить поведение, указав интерфейс после использования проекта Concrete. Легче протестировать.

Недостатки решения адаптера адаптера: вводит больше классов с небольшим преимуществом для производственного кода. Я не знаю, что делает Бетон, и может быть нецелесообразно обертывать Concrete в интерфейсе.

0

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

4

См. http://www.jmock.org/mocking-classes.html для информации о насмешливых классах и способах обхода окончательных ограничений.

+0

Не могли бы вы немного расширить этот ответ? Я не заметил, потому что вижу, что вы по-прежнему активным пользователем, и это старый ответ, но было бы полезно объяснить еще несколько объяснений. – Pops

0

Используйте более способный издевательский инструмент, такой как JMockit. Ваш тест может быть записано как:

@Test 
public void testFoo(final Concrete c) 
{ 
    final String s = "xxx"; 

    new Expectations() {{ 
    c.bar(s); 
    }}; 

    new ClassUnderTest().foo(c, s); 
} 

Для JMockit, это не имеет никакого значения, если Concrete является интерфейс, конечный класс, абстрактный класс, или любой другой. Кроме того, нет необходимости использовать @RunWith, расширить базовый тестовый класс или вызвать любой метод, например assertIsSatisfied(); все это делается автоматически, прозрачным способом.

 Смежные вопросы

  • Нет связанных вопросов^_^