在項目中,經(jīng)常要用到讀系統(tǒng)文件.在項目的遺留代碼中,都是在系統(tǒng)啟動是傳入一個APP_HOME,然后根據(jù)相對路徑去讀文件.這樣做的缺點(diǎn)是比較難測試,而且自動化的測試更難.

比如說有這樣一個類Server,要根據(jù)server.properties來初始化,一開始的代碼是這樣的:

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;

/**
* @author sting
*/
public class Server {
private static final String FILE = "conf" + File.separator + "server.properties";

public void initial() throws IOException {
FileInputStream in = new FileInputStream(System.getProperty("APP_HOME") + File.separator + FILE);
Properties properties = new Properties();
properties.load(in);
// initial
}
}

文件路徑和文件名都是hard code,很難測試. 我們首先把initial()重構(gòu)一下,代碼如下:


public void initial(InputStream in) throws IOException {
Properties properties = new Properties();
properties.load(in);
// initial
}

至少,測試時,我們可以傳進(jìn)來自己的InputStream,也可以方便的時候測試用的server.properties,或者干脆使用內(nèi)聯(lián)的文件,代碼如下:

class ServerTest extends TestCase {
private Server server;

public void setUp() throws Exception {
this.server = new Server();
}

public void testInitial() throws Exception {
String serverProperties = "port=8080\n" +
"run_mode=normal";
InputStream in = new ByteArrayInputStream(serverProperties.getBytes());

this.server.initial(in);
// assert
}
}

但是,在實際工作的代碼中,文件名和路徑依然要hard code進(jìn)代碼中.這時,我們可以使用spring中的Resource接口來進(jìn)一步改進(jìn)我們的代碼.

public class Server {
private Resource resource;

public void setResource(Resource r) {
this.resource = r;
}

public void initial() throws IOException {
Properties properties = new Properties();
properties.load(this.resource.getInputStream());
// initial
}
}

再加一段spring的配置文件:

<beans>
<bean id="server" class="Server">
<property name="resource" value="classpath:server.properties"/>
</bean>
</beans>

這樣,Server的代碼完全與文件的具體路徑和文件名無關(guān),僅僅用配置文件就可以指定,表達(dá)更清楚,也更易于測試.

當(dāng)然,僅限于已經(jīng)使用spring的項目.