# 1.UML圖

# 2.解釋
cts框架中將case的執行和case結果的收集分成了獨立的2個部分,我們稱case的結果的收集叫測試結果收集器。設計的思路來源為ddmlib中的ITestRunListener接口,該接口是一個抽象的觀察者組件,cts創建有很多的具體的組件。但是這些組件不是一個一個去注冊成為監聽者的,而是在run的時候傳遞給ddmlib中RemoteAndroidTestRunner類的。所以只要我們繼承了該接口,在run的時候把該接口的實例對象傳過去,我們就能在對象實例的相應方法中接受信息。但是我們想要有多個地方都能接受到測試結果呢?沒關系,cts為我們準備了ResultForwarder類。看具體實現細節:
# 3.ResultForwarder
~~~
public class ResultForwarder implements ITestInvocationListener {
private List<ITestInvocationListener> mListeners;
/**
* Create a {@link ResultForwarder} with deferred listener setting. Intended
* only for use by subclasses.
*/
protected ResultForwarder() {
mListeners = Collections.emptyList();
}
/**
* Create a {@link ResultForwarder}.
*
* @param listeners
* the real {@link ITestInvocationListener}s to forward results
* to
*/
public ResultForwarder(List<ITestInvocationListener> listeners) {
mListeners = listeners;
}
/**
* Alternate variable arg constructor for {@link ResultForwarder}.
*
* @param listeners
* the real {@link ITestInvocationListener}s to forward results
* to
*/
public ResultForwarder(ITestInvocationListener... listeners) {
mListeners = Arrays.asList(listeners);
}
/**
* Set the listeners after construction. Intended only for use by
* subclasses.
*
* @param listeners
* the real {@link ITestInvocationListener}s to forward results
* to
*/
protected void setListeners(List<ITestInvocationListener> listeners) {
mListeners = listeners;
}
/**
* Set the listeners after construction. Intended only for use by
* subclasses.
*
* @param listeners
* the real {@link ITestInvocationListener}s to forward results
* to
*/
protected void setListeners(ITestInvocationListener... listeners) {
mListeners = Arrays.asList(listeners);
}
/**
* {@inheritDoc}
*/
@Override
public void invocationStarted(IBuildInfo buildInfo) {
for (ITestInvocationListener listener : mListeners) {
listener.invocationStarted(buildInfo);
}
}
/**
* {@inheritDoc}
*/
@Override
public void invocationFailed(Throwable cause) {
for (ITestInvocationListener listener : mListeners) {
listener.invocationFailed(cause);
}
}
/**
* {@inheritDoc}
*/
@Override
public void invocationEnded(long elapsedTime) {
InvocationSummaryHelper.reportInvocationEnded(mListeners, elapsedTime);
}
/**
* {@inheritDoc}
*/
@Override
public TestSummary getSummary() {
// should never be called
return null;
}
/**
* {@inheritDoc}
*/
@Override
public void testLog(String dataName, LogDataType dataType,
InputStreamSource dataStream) {
// CLog.logAndDisplay(LogLevel.INFO,
// String.format("[testLog] dataName: %s", dataName));
for (ITestInvocationListener listener : mListeners) {
listener.testLog(dataName, dataType, dataStream);
}
}
/**
* {@inheritDoc}case開始時顯式的調用
*/
@Override
public void testRunStarted(String runName, int testCount) {
// CLog.logAndDisplay(LogLevel.INFO, String
// .format("[testRunStarted] runName: %s testCount:%d", runName,
// testCount));
for (ITestInvocationListener listener : mListeners) {
listener.testRunStarted(runName, testCount);
}
}
/**
* {@inheritDoc}
*/
@Override
public void testRunFailed(String errorMessage) {
// CLog.logAndDisplay(LogLevel.INFO,
// String.format("[testRunFailed] errorMessage: %s", errorMessage));
for (ITestInvocationListener listener : mListeners) {
listener.testRunFailed(errorMessage);
}
}
/**
* {@inheritDoc}
*/
@Override
public void testRunStopped(long elapsedTime) {
// CLog.logAndDisplay(LogLevel.INFO,
// String.format("[testRunStopped] elapsedTime: %d", elapsedTime));
for (ITestInvocationListener listener : mListeners) {
listener.testRunStopped(elapsedTime);
}
}
/**
* {@inheritDoc}
*/
@Override
public void testRunEnded(long elapsedTime, Map<String, String> runMetrics) {
// CLog.logAndDisplay(LogLevel.INFO,
// String.format("[testRunEnded] elapsedTime: %d", elapsedTime));
for (ITestInvocationListener listener : mListeners) {
listener.testRunEnded(elapsedTime, runMetrics);
}
}
/**
* {@inheritDoc}
*/
@Override
public void testStarted(TestIdentifier test) {
// CLog.logAndDisplay(LogLevel.INFO,
// String.format("[testStarted] %s", test.toString()));
for (ITestInvocationListener listener : mListeners) {
listener.testStarted(test);
}
}
/**
* {@inheritDoc}
*/
@Override
public void testFailed(TestFailure status, TestIdentifier test, String trace) {
// CLog.logAndDisplay(LogLevel.INFO,
// String.format("[testFailed] %s", test.toString()));
for (ITestInvocationListener listener : mListeners) {
listener.testFailed(status, test, trace);
}
}
/**
* {@inheritDoc}
*/
@Override
public void testEnded(TestIdentifier test, Map<String, String> testMetrics) {
// CLog.logAndDisplay(LogLevel.INFO,
// String.format("[testEnded] %s", test.toString()));
for (ITestInvocationListener listener : mListeners) {
listener.testEnded(test, testMetrics);
}
}
}
~~~
該類中繼承于ITestInvocationListener接口,ITestInvocationListener也繼承與ITestRunListener接口,然后在ITestRunListener接口原有的方法上添加了一些cts所要用到的方法。而我們的ResultForwarder就是一個ITestInvocationListener接口,自然而然也是ITestRunListener對象。
而我們具體看看ResultForwarder構造方法你會發現,參數是多個ITestInvocationListener對象,傳遞進來保存到定義的集合中。這樣當我們ResultForwarder傳遞到ddmlib內部的時候,ResultForwarder相應方法被調用后,里面的結果監聽器集合里的每一個結果監聽器都會收到結果。這樣的設計難道不是很牛逼,我是覺得很牛逼啊!!!
# 4.ResultForwarder的子類
cts還給測試時配備了3個使用型的失敗現場證據收集器,請看下面的三個類定義。
~~~
/**
* 保存bugreport日志 A {@link ResultForwarder} that will forward a bugreport on
* each failed test.
*/
private static class FailedTestBugreportGenerator extends ResultForwarder {
private ITestDevice mDevice;
public FailedTestBugreportGenerator(ITestInvocationListener listener, ITestDevice device) {
super(listener);
mDevice = device;
}
// 當ddmlib中ITestRunListener監聽器觸發testFailed方法時,該方法被調用.ITestRunListener的方法是由ddmlib內部調用的
// 該方法將在android-cts\repository\logs生成bugreport信息的文本文件并打包
@Override
public void testFailed(TestFailure status, TestIdentifier test, String trace) {
super.testFailed(status, test, trace);
InputStreamSource bugSource = mDevice.getBugreport();
// System.out.println("CtsTest.FailedTestBugreportGenerator.testFailed: 執行case失敗,需要保存當前bugreport的信息");
// CLog.logAndDisplay(LogLevel.INFO,
// String.format("[testFailed] %s", test.toString()));
super.testLog(String.format("bug-%s_%s", test.getClassName(), test.getTestName()), LogDataType.TEXT, bugSource);
bugSource.cancel();
}
}
/**
* 保存system緩沖區的日志 A {@link ResultForwarder} that will forward a logcat
* snapshot on each failed test.
*/
private static class FailedTestLogcatGenerator extends ResultForwarder {
private ITestDevice mDevice;
private int mNumLogcatBytes;
public FailedTestLogcatGenerator(ITestInvocationListener listener, ITestDevice device, int maxLogcatBytes) {
super(listener);
mDevice = device;
mNumLogcatBytes = maxLogcatBytes;
}
@Override
public void testFailed(TestFailure status, TestIdentifier test, String trace) {
super.testFailed(status, test, trace);
// sleep a small amount of time to ensure test failure stack trace
// makes it into logcat
// capture
RunUtil.getDefault().sleep(10);
InputStreamSource logSource = mDevice.getLogcat(mNumLogcatBytes);
super.testLog(String.format("logcat-%s_%s", test.getClassName(), test.getTestName()), LogDataType.TEXT, logSource);
logSource.cancel();
}
}
/**
* 保存截圖 A {@link ResultForwarder} that will forward a screenshot on test
* failures.
*/
private static class FailedTestScreenshotGenerator extends ResultForwarder {
private ITestDevice mDevice;
public FailedTestScreenshotGenerator(ITestInvocationListener listener, ITestDevice device) {
super(listener);
mDevice = device;
}
@Override
public void testFailed(TestFailure status, TestIdentifier test, String trace) {
super.testFailed(status, test, trace);
try {
InputStreamSource screenSource = mDevice.getScreenshot();
super.testLog(String.format("screenshot-%s_%s", test.getClassName(), test.getTestName()), LogDataType.PNG, screenSource);
screenSource.cancel();
} catch (DeviceNotAvailableException e) {
// TODO: rethrow this somehow
CLog.e("Device %s became unavailable while capturing screenshot, %s", mDevice.getSerialNumber(), e.toString());
}
}
}
~~~
老大:bugreport信息保存
老二:logcat信息保存
老三:現場截圖
- 前言
- (1)-windows下cts配置
- (2)-cts調試環境的搭建
- (3)-基礎庫tradefederation配置
- (4)-任務的添加
- (5)-9大組件配置
- (6)-任務的執行
- (7)-任務執行的調度室
- (8)-IBuildProvider
- (9)-IDeviceRecovery
- (10)-TestDeviceOptions
- (11)-ICommandOptions
- (12)-ITargetPreparer
- (13)-任務執行過程
- (14)-任務執行過程
- (15)-任務執行完
- (16)-logcat信息收集系統
- (17)-fastboot狀態監聽器
- (18)-設備恢復
- (19)-設備狀態的分類以及恢復模式的分類
- (20)-cts自身log系統
- (21)-測試結果收集系統
- (22)-自動檢測設備
- (23)-設備分類
- (24)-case的組織