從上圖能夠清楚的看出Junit大體分爲幾個版塊,接下來一一簡略介紹這些版塊的做用。java
runner:定義了Junit模型中的許多基本概念,只要是一些虛類和接口,是整個Junit工程的基石git
runners:提供了從註解中使用反射完成測試用例執行的實現github
interval:提供了在Runner中許多虛類的默認實現,包括各種RunnerBuilder如基於註解提供Builder、各種Matchers、各種Request如類測試Request、方法測試Request。安全
rules:用於用戶自定義擴展,規定對於不一樣statement的用戶自定義行爲app
matchers:主要用於AssertThat方法,在4.4以後廢棄框架
validator:從類、方法和域多個方面檢查測試樣例ide
experimental:一些測試特性測試
Runner:以Notifier爲參數容許測試樣例,運行過程當中的Notifier負責監視測試過程ui
Request:負責記錄測試樣例的Description信息,同事負責提供對應的Runner。能夠經過Computer結合指定或默認的RunnerBuilder來直接爲一系列測試類統一提供Runnerthis
Description:描述測試樣例,使用Composite模式,組合多個樣例
Result:記錄異常和失敗,內置一個Listener來實現與測試過程的同步,測試完成時count自增,有樣例失敗則加入Failure列表
Failure:將斷言失敗和拋出異常綜合在同一個框架下,同時提供了Description的信息
Listener:監視測試過程,典型的觀察者模式
Notifier:管理一系列Listener,保證線程安全
Filter:指定條件,只運行符合條件的測試樣例,能夠動態添加,爲每次測試增長了靈活性
JunitCore負責提供給用戶統一的交互,從命令行運行測試樣例。Notifier是一個虛類,子類須要實現如何通知Listener的方法,負責管理Listener集合,內部內置了一個靜態的SafeNotifier,該類提供了一個run方法,來簡單依次通知全部Listener,它用來實如今測試開始和失敗出現的時候通知全部Listener。
Description是對測試樣例的建模,用來組合多個測試樣例,是Runner中的核心內容。
Filter也是一個虛類,子類應該實現shouldRun方法來決定對於Description是否運行。同時依然實現一個靜態方法來提供什麼都不過濾,以及一個判斷原子描述是否等於指望描述的過濾器,對於非原子描述若其子描述均不等於指望描述則濾掉。以下列代碼所示:
/** * Returns a {@code Filter} that only runs the single method described by * {@code desiredDescription} */ public static Filter matchMethodDescription(final Description desiredDescription) { return new Filter() { @Override public boolean shouldRun(Description description) { if (description.isTest()) { return desiredDescription.equals(description); } // explicitly check if any children want to run for (Description each : description.getChildren()) { if (shouldRun(each)) { return true; } } return false; } @Override public String describe() { return String.format("Method %s", desiredDescription.getDisplayName()); } }; }
Failure組合了Description和Throwable,爲運行時異常和斷言錯誤屏蔽了不一致的方面,能夠向上提供錯誤信息和樣例信息。
Request負責提供具體的Runner來run對應的測試樣例,同時是Filter做用的主體,對於Filter,會返回一個新的FilterRequest,代碼以下:
package org.junit.internal.requests; import org.junit.internal.runners.ErrorReportingRunner; import org.junit.runner.Request; import org.junit.runner.Runner; import org.junit.runner.manipulation.Filter; import org.junit.runner.manipulation.NoTestsRemainException; /** * A filtered {@link Request}. */ public final class FilterRequest extends Request { private final Request request; /* * We have to use the f prefix, because IntelliJ's JUnit4IdeaTestRunner uses * reflection to access this field. See * https://github.com/junit-team/junit/issues/960 */ private final Filter fFilter; /** * Creates a filtered Request * * @param request a {@link Request} describing your Tests * @param filter {@link Filter} to apply to the Tests described in * <code>request</code> */ public FilterRequest(Request request, Filter filter) { this.request = request; this.fFilter = filter; } @Override public Runner getRunner() { try { Runner runner = request.getRunner(); fFilter.apply(runner); return runner; } catch (NoTestsRemainException e) { return new ErrorReportingRunner(Filter.class, new Exception(String .format("No tests found matching %s from %s", fFilter .describe(), request.toString()))); } } }
JUnitCore使用外觀模式(facade),對外提供一致的界面,同時支持運行JUnit 4或JUnit 3.8.x用例,經過命令行執行用例.首先它使用jUnitCommandLineParseResult解析外部參數,將默認的TextListener加入內置的Notifier。它所運行的Runner也是由jUnitCommandLineParseResult提供的,先行經過測試filter掉不須要的樣例,最後調用Runner的run方法。