2016-09-29 78 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」的實例。 = >不需要嘗試嘲笑多餘的東西。