2015-04-15 155 views
0

我扔這個隨機主題道歉,但我沒有想出一個更好的名字,如何有效測試此代碼?

class ReportSenderRunnable implements Runnable { 

    private final LPLogCompressor compressor; 

    public ReportSenderRunnable(final LPLogCompressor compressor) { 
     this.compressor = compressor; 
    } 

    @Override 
    public void run() { 
     executeTasks(); 
    } 

    private void executeTasks() { 
     try { 
//  compressor.compress(); 
     reportStatus = ReportStatus.COMPRESSING; 
     System.out.println("compressing for 10 seconds"); 
     Thread.sleep(10000); 
     } catch (final IllegalStateException e) { 
     logCompressionError(e.getMessage()); 
     } /*catch (final IOException e) { 
     logCompressionError(e.getMessage()); 
     }*/ catch (InterruptedException e) { 
     logCompressionError(e.getMessage()); 
     } 

     try { 
     reportStatus = ReportStatus.SENDING; 
     System.out.println("sending for 10 seconds"); 
     Thread.sleep(10000); 
     } catch (final InterruptedException e) { 
     reportStatus = ReportStatus.EXCEPTION_IN_SENDING; 
     } 

     try { 
     reportStatus = ReportStatus.SUBMITTING_REPORT; 
     System.out.println("submitting report for 10 seconds"); 
     Thread.sleep(10000); 
     } catch (final InterruptedException e) { 
     reportStatus = ReportStatus.EXCEPTION_IN_SUBMITTING_REPORT; 
     } 
     System.out.println("Report Sender completed"); 
     reportStatus = ReportStatus.DONE; 
    } 

    private void logCompressionError(final String cause) { 
     logError(ReportStatus.COMPRESSING, cause); 
     reportStatus = ReportStatus.EXCEPTION_IN_COMPRESSION; 
    } 

    private void logError(final ReportStatus status, final String cause) { 
     LOGGER.error("{} - {}", status, cause); 
    } 
    } 

理想的情況下,之類的語句

System.out.println("sending for 10 seconds"); 
Thread.sleep(10000); 

將通過實際的任務所取代,但現在假設這是這種情況,它們的運行方式是

private void submitJob() { 
    final ExecutorService executorService = Executors.newSingleThreadExecutor(); 
    try { 
     final LPLogCompressor lpLogCompressor = getLpLogCompressor(); 
     executorService.execute(getReportSenderRunnable(lpLogCompressor)); 
    } catch (final IOException e) { 
     reportStatus = ReportStatus.EXCEPTION_IN_COMPRESSION; 
     LOGGER.debug("Error in starting compression: {}", e.getMessage()); 
    } 
    System.out.println("started Report Sender Job"); 
    } 

我的問題是如何有效地測試此代碼?我寫的是

@Test 
    public void testJobAllStages() throws InterruptedException, IOException { 
    final ReportSender reportSender = spy(new ReportSender()); 
    doReturn(compressor).when(reportSender).getLpLogCompressor(); 
    when(compressor.compress()).thenReturn("nothing"); 
    reportSender.sendAndReturnStatus(); 
    Thread.sleep(10); 
    assertEquals(ReportStatus.COMPRESSING, reportSender.getCurrentStatus()); 
    Thread.sleep(10000); 
    assertEquals(ReportStatus.SENDING, reportSender.getCurrentStatus()); 
    Thread.sleep(10000); 
    assertEquals(ReportStatus.SUBMITTING_REPORT, reportSender.getCurrentStatus()); 
    } 

這對上面的代碼運行良好。 對我來說這是蹩腳的理由如下

  1. 並非所有任務將採取同時在理想的情況下
  2. 測試與Thread.sleep會花費太多時間,也增加了不確定性。

問題

  1. 如何有效地測試呢?
+1

想必你'ReportSender'將調用一些服務上的方法 - 壓縮服務器,發送服務。模擬這些服務並測試這些方法是否被調用,並且它們是以正確的順序調用的。 –

+0

謝謝@BoristheSpider對你的話,我對代碼做了修改並添加了答案 – daydreamer

回答

0

基於@Boris the Spider評論,我利用嘲笑和這裏是我的測試樣子

@Mock 
    private ReportSenderRunnable reportSenderRunnable; 

    @Mock 
    private LPLogCompressor compressor; 

    @Before 
    public void setUp() throws Exception { 
    MockitoAnnotations.initMocks(this); 
    } 

    @Test(timeout = 1000) 
    public void testJobNoException() throws InterruptedException, IOException { 
    final ReportSender reportSender = spy(new ReportSender()); 
    doReturn(compressor).when(reportSender).getLpLogCompressor(); 
    when(compressor.compress()).thenReturn("nothing"); 
    reportSender.sendAndReturnStatus(); 
    Thread.sleep(10); 
    assertEquals("Job must be completed successfully", ReportStatus.DONE, 
       reportSender.getCurrentStatus()); 
    } 

    @Test(timeout = 1000) 
    public void testJobWithIllegalStateException() throws Exception { 
    final ReportSender reportSender = spy(new ReportSender()); 
    doReturn(compressor).when(reportSender).getLpLogCompressor(); 
    doThrow(IllegalStateException.class).when(compressor).compress(); 
    reportSender.sendAndReturnStatus(); 
    Thread.sleep(10); 
    assertEquals("Job must failed during compression", ReportStatus.EXCEPTION_IN_COMPRESSION, 
       reportSender.getCurrentStatus()); 
    } 
0

您可以使用接受Callable的方法(例如TimedAssertion.waitForCallable)添加一個類,然後使用ExecutorService每秒執行一次Callable,直到它返回true。如果它在特定的時間內沒有返回,它就會失敗。

你可以這樣調用該類從測試這樣的:

boolean result; 
result = new TimedAssertion().waitForCallable(() -> 
    reportSender.getCurrentStatus() == ReportStatus.COMPRESSING); 
assertTrue(result); 
result = new TimedAssertion().waitForCallable(() -> 
    reportSender.getCurrentStatus() == ReportStatus.SENDING); 
assertTrue(result); 

...等。這樣,您可以輕鬆地等待代碼中的特定狀態爲true,而無需等待太久 - 您可以在需要此類斷言的任何地方重新使用此新類。