天天看點

使用jmock測試System.in和System.out

本文要求讀者已具備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);
     }
}