2016-09-29 73 views
0

我想为以InvocationContext为参数的方法编写一个单元测试。更具体地说,这是该方法的签名和要领。如何获得单元测试的InvocationContext的实例

@AroundInvoke 
public Object autoLogMethodCall(final InvocationContext context) throws Exception { 

    String className = context.getClass().getSimpleName(); 
    String packageName = context.getClass().getPackage().getName(); 
    String methodName = context.getMethod().getName(); 

    // Some logging stuff that is the target of actual testing 
} 

正如你看到的,它是一个拦截器方法,我打算用做某些方法调用一些基本的日志记录。

然后我有单元测试,我想测试记录的消息将被正确格式化。但问题是我无法创建一个InvocationContext的实例作为测试参数传递。

我试过下面的嘲弄。

@RunWith(PowerMockRunner.class) 
public class AutoLoggingTest extends TestCase { 

    @Test 
    public void testAutoLogger() { 
     Logger log = new MyLogger(); // This is an implementation of org.apache.logging.log4j.Logger, which will hold the generated messages to check at the test 
     InvocationContext mockContext = PowerMockito.mock(InvocationContext.class); 
     Class clazz = AutoLoggingTest.class; 
     // The row causing the error 'MissingMethodInvocation' 
     PowerMockito.when(mockContext.getClass()).thenReturn(clazz); 

try { 
    InterceptingClass ic = new InterceptingClass(); 
    ic.setLogger(log); 
    ic.autoLogMethodCall(mockContext); 
    MyLogger myLogger = (MyLogger) ic.getLogger(); 
    assertEquals(2, myLogger.getMessages().size()); 
     } catch (Exception e) { 
      e.printStackTrace(); 
      fail("Should not cause an exception in any case"); 
     } 
    } 
    // Check the actual messages based on the information given in mocked InvocationContext object 
} 

但它不起作用。
原因:

Tests in error: AutoLoggingTest.testAutoLogger:25 » MissingMethodInvocation.
when() requires an argument which has to be 'a method call on a mock'.).

如何做正确的嘲讽任何意见?

回答

0

这需要一些开箱即用的思维。一些与模拟的InvocationContext混合的内容是必需的。我们可以提供测试类本身的嘲笑InvocationContext对象,因此,我添加和更改在测试类的以下内容:

​​

此外,我意识到我应该为“MyLogger”提供代码:这不是什么对于测试来说实现起来相当简单。

// Logger = org.apache.logging.log4j.Logger 
// ExtendedLoggerWrapper = org.apache.logging.log4j.spi.ExtendedLoggerWrapper 
@SuppressWarnings("serial") 
protected class MyLogger extends ExtendedLoggerWrapper implements Logger { 
    private List<String> messages; 

    public MyLogger() { 
     super(null, null, null); 
     this.clearMessages(); 
    } 

    // The actual log calls need to get stored to store the messages + prevent from NullPointerExceptions 
    @Override 
    public void trace(String msg) { 
     messages.add(msg); 
    } 

    // The actual log calls need to get stored to store the messages + prevent from NullPointerExceptions 
    @Override 
    public Object exit(Object obj) { 
     messages.add("Exited with: " + obj); 
     return obj; 
    } 

    public List<String> getMessages() { 
     return this.messages; 
    } 

    public void clearMessages() { 
     messages = new ArrayList<>(); 
    } 

    /** 
    * You need to override all the method calls used to prevent NullPointerExceptions. 
    * 
    * @return <code>True</code> always, as required so in test. 
    */ 
    @Override 
    public boolean isTraceEnabled() { 
     return true; 
    } 
} 

而且因为是在原来的日志类需要一些小的重构,现在看起来是这样的:

public abstract class AutoLoggingUtility { 

    private static final String logEntryTemplate = "Call to: %1$s#%2$s"; 
    private static final String logExitTemplate = "'%1$s' call duration: %2$s ms"; 

    public AutoLoggingUtility() { 

    } 

    @AroundInvoke 
    public Object autoLogMethodCall(final InvocationContext context) throws Exception { 
    // Note the methods Overridden in MyLogger 
    if (this.getLogger().isTraceEnabled()) { 
     String methodName = null; 
     String className = null; 
     try { 
      Method method = context.getMethod(); 
      methodName = method.getName(); 
      // Contains package 
      className = context.getMethod().getDeclaringClass().getName(); 
      } catch (Exception e) { 
       // May not crash 
       methodName = "?method?"; 
       className = "?class?"; 
      } 
      Object[] args1 = { className, methodName }; 
      String logMsg = String.format(getLogentrytemplate(), args1); 
      this.getLogger().trace(logMsg); 

      long startTime = System.currentTimeMillis(); 
      try { 
      return this.getLogger().exit(context.proceed()); 
      } finally { 
      Object[] args2 = { methodName, System.currentTimeMillis() - startTime }; 
      logMsg = String.format(getLogexittemplate(), args2); 
      this.getLogger().trace(logMsg); 
     } 
    } else { 
     // mocked 
     return context.proceed(); 
    } 

    /** 
    * Forces each extending class to provide their own logger. 
    * 
    * @return The logger of the extending class to direct the messages to correct logging context. 
    */ 
    abstract Logger getLogger(); 
} 

的“AutoLoggingUtilityImplForTesting”只是延伸“AutoLoggingUtility”持有实例MyLogger

Summarum:
诀窍是用于嘲笑对象的时候,“getMethod()”被称为返回提供的测试类方法“methodForLoggingTesting”的实例。 = >不需要尝试嘲笑多余的东西。