本文要求讀者已具備juit和jmock基礎
在TDD過程中需要測試代碼中的System.in和System.out。
技術難點包括
1、mock宿主還原
2、inout參數的行為模拟
3、mock system.in和out
1、測試主體
@Service
class ConsoleManagerBizImpl{
private static Logger LOGGER = Logger
.getLogger(ConsoleManagerBizImpl.class);
public String readLine() {
final Scanner scanner = new Scanner(System.in);
String lineMessage = null;
while (!StringUtils.hasText(lineMessage)) {
lineMessage = scanner.nextLine();
}
return lineMessage;
}
public void writeLine(final String toWrite) {
LOGGER.info(toWrite);
}
}
2、測試類
public class ConsoleManageBizImplTest {
@Autowired
private ConsoleManagerBizImpl biz;
/**
* 既可 mock 接口也可以 mock 類
*/
protected final Mockery context = new JUnit4Mockery() {
{
setImposteriser(ClassImposteriser.INSTANCE);
}
};
/**
* 改變預期的參數
*
* @param result
* 預期結果
* @return 行為
*/
public Action ChangeBytes(final byte[] result) {
return new ChangeBytesAction(result);
}
/**
* Test method for {@link ConsoleManagerBizImpl#readLine()}.
*
* @throws IOException
* 異常
*/
@Test
public void testReadLine() throws IOException {
final InputStream origin = System.in;
final InputStream mockStream = context.mock(InputStream.class);
System.setIn(mockStream);
context.checking(new Expectations() {
{
final byte[] b = new byte[8192];
oneOf(mockStream).read(b, 0, 8192);
final byte[] result = new byte[8192];
result[0] = '1';
result[1] = '1';
result[2] = '\n';
will(ChangeBytes(result));
}
});
Assert.assertEquals("11", biz.readLine());
System.setIn(origin);
}
/**
* Test method for {@link ConsoleManagerBizImpl#writeLine(String)}
*/
@Test
public void testWriteLine() {
final String toWrite = "109-230-912-0";
biz.writeLine(toWrite);
}
}
3、mockaction
class ChangeBytesAction implements Action {
private final byte[] result;
/**
* @param result
* 結果
*/
public ChangeBytesAction(final byte[] result) {
this.result = result;
}
/*
* (non-Javadoc)
*
* @see org.hamcrest.SelfDescribing#describeTo(org.hamcrest.Description)
*/
public void describeTo(final Description description) {
description.appendText("change ").appendValueList("", ", ", "", result)
.appendText(" value");
}
/*
* (non-Javadoc)
*
* @see org.jmock.api.Invokable#invoke(org.jmock.api.Invocation)
*/
public Object invoke(final Invocation invocation) throws Throwable {
final byte[] bytesArray = (byte[]) invocation.getParametersAsArray()[0];
for (int i = 0; i < result.length; i++) {
bytesArray[i] = result[i];
}
return result.length;
}
}
4、如果在測試主體中使用System.out輸出,則下面的代碼可以對其進行測試
/**
* Test method for {@link ConsoleManagerBizImpl#writeLine(String)}
*/
@Test
public void testWriteLine() {
final PrintStream origin = System.out;
final PrintStream mockout = context.mock(PrintStream.class);
System.setOut(mockout);
final String toWrite = "109-230-912-0";
context.checking(new Expectations() {
{
oneOf(mockout).println(toWrite);
}
});
biz.writeLine(toWrite);
System.setOut(origin);
}
}