Problem
假如我們有一隻main程式,它在執行完某些工作後會dump資訊到console上,我們要怎麼做verify? 假設程式如下,我們的測試程式所期望的輸出就是HelloWorld。
public class Example { public static void main(String[] args) { System.out.println("Hello World"); } }
How to verify?
是否能夠透過PowerMock達到目的呢? 答案是可以的,但非常麻煩。你必須先mock system.out物件,接著針對可能會呼叫到的println或print做去set expectResult。我提供另外一種方法,可以讓你直接針對結果做assertion,步驟如下:
- 建立mock的PrintStream類別且override write method,System.out的print method最後都會呼叫write method。
- 建立mock的OutputStream類別,用來設置給PrintStream使用。而此mock OutputStream物件需要override write method,將寫入的int轉放入StrinBuffer中,好讓最後我們可以直接透過此StringBuffer做驗證。
- 在測試案例中,將mock的PrintStream物件設至System.out中。
- 驗證mock PrintStream所儲存起來的資訊。
我們來看看實做。
Implement Mock PrintStream
在mock PrintStream建構子的地方,super讓它使用原本的System.out就好,這並不是很重要。重要的是我們要將client用來驗證的OutputStream給設成member,而write的地方要將傳入值給帶給OutputStream物件中,好讓它最後可以透過我們假的OutputStream做寫入動作。
import java.io.IOException; import java.io.OutputStream; import java.io.PrintStream; public class TheTestingPrintStream extends PrintStream{ private OutputStream mOutputStream; public TheTestingPrintStream(OutputStream aOutputStream) { super(System.out); System.out.println(); mOutputStream=aOutputStream; } @Override public void write(int aB) { super.write(aB); try { mOutputStream.write(aB); } catch (IOException e) { e.printStackTrace(); } } @Override public void write(byte[] aBuf, int aOff, int aLen) { super.write(aBuf, aOff, aLen); try { mOutputStream.write(aBuf,aOff, aLen); } catch (IOException e) { e.printStackTrace(); } } }
Implement Mock OutputStream
而Mock OutputStream的職責就是將要寫入的字元透過StringBuffer存起來即可。
import java.io.IOException; import java.io.OutputStream; public class StringBufferOutputStream extends OutputStream { private StringBuffer mStringBuffer; public StringBufferOutputStream(StringBuffer aSb) { mStringBuffer = aSb; } @Override public void write(int aB) throws IOException { mStringBuffer.append((char) aB); } public String toString() { return mStringBuffer.toString(); } public void clear() { mStringBuffer.delete(0, mStringBuffer.length()); } }
Implement Testing Code
在Setup的時候,我們透過System.setOut將PrintStream給偷天換日掉。這樣就可以在呼叫完Example.main後,從mSB中取得結果去做Assertion。
import org.junit.Assert; import org.junit.Before; import org.junit.Test; public class ExampleTest { private StringBuffer mSB = new StringBuffer(); private StringBufferOutputStream mSBOutputStream = new StringBufferOutputStream(mSB); @Before public void setUp() throws Exception { System.setOut(new TheTestingPrintStream(mSBOutputStream)); mSBOutputStream.clear(); } @Test public void testMain(){ Example.main(new String[0]); Assert.assertEquals("Hello World"+System.getProperty("line.separator"), mSB.toString()); } }
後記
若懶得寫可以直接使用opensource: link。
留言
張貼留言