2016-12-29 53 views
0

我有下面的代碼處理數據的方法:測試讀取和從文件

public class FolderServiceImpl implements FolderService { 

    private static final Logger L = LoggerFactory.getLogger(FolderServiceImpl.class); 

    public int getStatus(String folderPath) { 
     int status = 0; 
     File folderStatusFile = new File(folderPath, ".folderstatus"); 
     if (folderStatusFile.exists()) { 
      BufferedReader br = null; 
      try { 
       br = new BufferedReader(new FileReader(folderStatusFile)); 
       String line = br.readLine(); 
       status = Integer.parseInt(line); 
      } catch (Exception e) { 
       L.error("can't read file " + folderStatusFile.getAbsolutePath(), e); 
       status = 4; 
      } finally { 
       if (br != null) { 
        try { 
         br.close(); 
        } catch (IOException e) { 
         L.warn("could not close reader ", e); 
        } 
       } 
      } 

     } else { 
      status = 3; 
     } 
     return status; 
    } 
} 

我想不爲任何情況下創建實際的文件來測試這種方法。我應該使用Java 1.7,JUnit 4,Mockito和/或PowerMockito。

關於如何做到這一點的任何想法?

我說的是嘲笑數據源或者簡單地改變方法的輸入。

我的測試看起來是這樣的:

`@rule 公共TemporaryFolder文件夾=新TemporaryFolder();

private FolderServiceImpl serviceToTest = new FolderServiceImpl(); 

private String folderPath; 

@Before 
public void setUp() { 
    folderPath = folder.getRoot().getAbsolutePath(); 
    try { 
     folder.newFile(".folderstatus"); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 

} 

@Test 
public void shouldReturnFolderStatus3WhenFolderStatusIsNotFound() { 
    // given 
    deleteFolderStatusFile(); 

    // actual 
    int status = serviceToTest.getFolderStatus(folderPath); 

    // expected 
    assertEquals(3, status); 
} 

@Test 
public void shouldReturnFolderStatus4WhenTheStatusIsUnreadable() { 
    // given 
    writeStatusToTestFile("Test"); 

    // actual 
    int status = serviceToTest.getFolderStatus(folderPath); 

    // expected 
    assertEquals(4, status); 
} 

@Test 
public void shouldReturnFolderStatusInTheFile() { 
    // given 
    writeStatusToTestFile("1"); 

    // actual 
    int status = serviceToTest.getFolderStatus(folderPath); 

    // expected 
    assertEquals(1, status); 

} 

private void writeStatusToTestFile(String status) { 
    Path file = Paths.get(folder.getRoot().getAbsolutePath(), ".folderstatus"); 
    try { 
     Files.write(file, status.getBytes()); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
} 

private void deleteFolderStatusFile() { 
    Path file = Paths.get(folder.getRoot().getAbsolutePath(), ".folderstatus"); 
    try { 
     Files.delete(file); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
}` 

回答

0

雖然@BenHeid的答案可能工作的我d建議改用不同的方法。

恕我直言,當我使用PowerMock(-ito)它是一個不好的設計投降。 另外,PowerMock解決方案會混淆測試覆蓋率工具,因爲它會在測試覆蓋率後進行應用字節代碼的更改。


所以我喜歡的方式就是堅持清潔守則和OOP規則。

其中之一是分離關注

在你的情況下,該方法創建一些基礎設施類(依賴關係),即FileReaderBufferedReader

但(直接)依賴關係的實例化不是包含業務邏輯的類的責任。

所以我建議要進行重構的代碼到一個單獨的類:

class ReaderFactory { 
    public BufferedReader createFor(File file) throws FileNotFoundException { 
     return new BufferedReader(new FileReader(file)); 
    } 
} 

你的類將改成這樣:

class FolderServiceImpl { 
    private static final Logger L = LoggerFactory.getLogger(FolderServiceImpl.class); 
    private final ReaderFactory readerFactory; 

    FolderServiceImpl(ReaderFactory readerFactory) { 
     this.readerFactory = readerFactory; 
    } 

    public int getStatus(String folderPath) { 
     int status = 0; 
     File folderStatusFile = new File(folderPath, ".folderstatus"); 
     // try "with resource" takes care of closing the reader 
     try (BufferedReader br = readerFactory.createFor(folderStatusFile);) { 
      String line = br.readLine(); 
      status = Integer.parseInt(line); 
     } catch (IOException e) { 
      status = 3; 
     } catch (Exception e) { 
      L.error("can't read file " + folderStatusFile.getAbsolutePath(), e); 
      status = 4; 
     } 
     return status; 
    } 
} 

和你的測試將是這樣的:

public class FolderServiceImplTest { 

    private static final String ANY_FILE_NAME = ""; 

    @Rule 
    public MockitoRule mockitoRule = MockitoJUnit.rule(); 

    @Rule 
    public ExpectedException thrown = ExpectedException.none(); 

    @Mock 
    private ReaderFactory readerFactory; 

    @InjectMocks 
    FolderServiceImpl sut; 

    @Test 
    public void getStatus_FileNotExisting_returnStatus3() throws Exception { 
     // arrange 
     Mockito.doThrow(new FileNotFoundException("UnitTest")).when(readerFactory).createFor(Mockito.any(File.class)); 
     // act 
     int status = sut.getStatus(ANY_FILE_NAME); 
     // assert 
     Assert.assertThat("status",status,CoreMatchers.equalTo(3)); 
    } 

    @Test 
    public void getStatus_ValidFile_returnFileContentAsInt() throws Exception { 
     // arrange 
     BufferedReader bufferedReader = Mockito.mock(BufferedReader.class); 
     Mockito.doReturn(bufferedReader).when(readerFactory).createFor(Mockito.any(File.class)); 
     Mockito.doReturn("4711").when(bufferedReader).readLine(); 
     // act 
     int status = sut.getStatus(ANY_FILE_NAME); 
     // assert 
     Assert.assertThat("status",status,CoreMatchers.equalTo(4711)); 
    } 
} 
+0

我相信'IOException'應該用'FileNotFoundException'來更改 – radumach

+0

@radumach是的,謝謝,我改變了答案。 –

0

你必須使用這樣的事情:

@RunWith(PowerMockRunner.class) 
@PrepareForTest(tests.class) 
public class test { 

@Test 
public void test() throws Exception { 
    File fileMock = Mockito.mock(File.class); 
    PowerMockito.whenNew(File.class).withArguments(Mockito.anyString(), Mockito.anyString()).thenReturn(fileMock); 
    FolderServiceImpl sut = new FolderServiceImpl sut(); 
    Mockito.when(fileMock.exists()).thenReturn(true); 
    sut.getStatus(""); 

// Your verifications.. 
} 
} 

Powermock會嘲笑這是在你的類的方法創建的getStatus File對象。用Mockito.when你可以說你的代碼中folderStatusFile.exists()的返回值是什麼。

編輯

我已經包含以下兩個罐子使用Maven,但你並不需要使用Maven:https://mvnrepository.com/artifact/org.powermock/powermock-module-junit4/1.4.6https://mvnrepository.com/artifact/org.powermock/powermock-api-mockito/1.4.9https://mvnrepository.com/artifact/org.mockito/mockito-all/1.10.19

+0

我現在不是如果我正確運行它,但是,這種方法得到'java.lang.IncompatibleClassChangeError:Found interfa ce org.powermock.api.mockito.internal.mockcreation.MockCreator,但期望類。此外,測試的想法是驗證給定不同情況下的預期結果(沒有預設文件,沒有寫入int文件,有一些int寫入文件)。 – radumach

+0

我編輯我的帖子,並添加必要的罐子。也許你已經包括了錯誤。 – BenHeid

+0

我在我的類路徑中有那些確切的依賴關係,並且我得到相同的錯誤 – radumach