2013-04-19 5 views
3

Для теста интеграции мне нужно высмеять конкретный метод в клиенте java-сервиса, не уничтожая остальную информацию в нем. Он не имеет собственного конструктора, поэтому решение, как это может быть и речи:Можно ли издеваться над одним методом в уже существующем объекте?

private DBClient mockClient = new DBClient(alreadyExistingClient){ 
    @Override 
    void deleteItem(Item i){ 
     //my stuff goes here 
    } 
}; 

Есть ли способ, чтобы дразнить метод DeleteItem таким образом, что учетные данные, конечные точки, и т.д. ... сохранены в существующий Объект DBClient?

редактировать: Mockito не доступен для использования в данном случае

+3

'mockito' был не упоминается тег, но он предлагает [шпион рутина] (HTTP: //mockito.googlecode.com/svn/branches/1.5/javadoc/org/mockito/Mockito.html#spy (T)) для этой цели –

+0

Возможный дубликат [Powermock - как издеваться над определенным методом и оставить остальную часть объект как есть] (http://stackoverflow.com/questions/9305167/powermock-how-to-mock-a-specific-method-and-leave-the-rest-of-the-object-as-is) –

+0

В этом случае Mockito не является доступной структурой. – AdamSpurgin

ответ

5

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

Это пример того, как перехватить метод Set.add(), вы можете сделать то же самое для deleteItem()

package example.dynamicproxy; 

import java.lang.reflect.InvocationHandler; 
import java.lang.reflect.Method; 
import java.lang.reflect.Proxy; 
import java.util.Set; 

public class SetProxyFactory { 

    public static Set<?> getSetProxy(final Set<?> s) { 
     final ClassLoader classLoader = s.getClass().getClassLoader(); 
     final Class<?>[] interfaces = new Class[] {Set.class}; 
     final InvocationHandler invocationHandler = new InvocationHandler() { 

      @Override 
      public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { 

       if (method.getName().equals("add")) { 
        System.out.println("add() intercepted"); 
        // do/return whatever you want 
       } 

       // or invoke the real method 
       return method.invoke(s, args); 
      } 
     }; 

     final Object proxy = Proxy.newProxyInstance(classLoader, interfaces, invocationHandler); 

     return (Set<?>) proxy; 
    } 
} 
+1

Я даже не знал, что это возможно, и это определенно работает для ситуации здесь. Спасибо, что опубликовали это, даже если я не использую его, я многому научился. – AdamSpurgin

+0

Интересное решение. Вы все еще можете проверить, существует ли опасный метод до того, как вы создадите прокси-сервер. Чтобы убедиться, что он не был не переименован. –

2

Вы могли бы пойти лоу-фай и создать подкласс класса DBClient. В этот подкласс передайте экземпляр DBClient, который вы хотите высмеять.

Использовать композицию внутри подкласса и делегировать все вызовы методов исходному DBClient, кроме тех, которые вы хотите высмеять. Добавьте свою макетную реализацию в нужный метод.

Это не так много, как насмешливый фреймворк, но он должен работать.

DBClient mockDbClient = new DBClient() { 
    private DBClient dbClientDelegate; 

    public void setDelegate(DBClient dbClient) { 
     dbClientDelegate = dbClient; 
    } 

    //override all methods. 
    //delegate to the corresponding method of the dbClientDelegate instance 

    //overide the method you want to mock, add asserts for method arguments 
    //return mock data as appropriate 

} 

mockDbClient.setDelegate(preinstantiatedDbClient); 
//inject mockDbClient to test class 
//call test class/method 

Надеюсь, это поможет.

+0

Я пытался избежать этого, но похоже, что это единственный вариант, который у меня есть в этом случае. К счастью, это довольно изолированная ситуация, и мне больше никогда не придется делать что-либо подобное. – AdamSpurgin

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