Quarkus入门
Quarkus – 一個為OpenJDK HotSpot和GraalVM量身定制的Kubernetes本機Java堆棧,它是從最佳Java庫和標準中精制而成的。 –是一個容器優先的框架,針對快速啟動時間和低內存消耗進行了優化。 該框架基于許多流行的Java庫構建,并且為構建標準REST以及響應式和消息驅動型微服務提供支持。 由于快速的啟動時間和較低的內存使用量,Quarkus還可以用于在無服務器環境中實現功能。 憑借統一的配置,出色的實時重新加載功能和工具支持,Quarkus為快速開發應用程序提供了許多可能性。
了解如何開始使用Quarkus和構建PetClinic REST API。
這篇博客文章涵蓋:
- 開發環境要求
- 建立新專案
- 使用Java 11開發,構建和運行應用程序
- 使用Postgres和Flyway進行數據源配置
- 分頁CRUD服務
- 創建集成測試
- 實時重新加載和調試
- Docker化應用程序(本機和非本機)
關于PetClinic API
我決定重新使用在本博客文章Spring Boot和Spring Data REST中使用的PetClinic模型。
基本上,這是一個基本的CRUD服務,用于管理虛構的PetClinic:寵物,獸醫,來訪等。
先決條件
碼頭工人
Docker將用于運行服務本身的dockerized版本,但也將用于運行PostgreSQL服務器。
帶有GraalVM的JDK 11
PetClinic API將使用Java 11構建,因此必須安裝JDK 11。 為了構建本機可執行文件,必須提供GraalVM 19.3+,并且由于它是基于OpenJDK 11構建的,因此這將是本教程的最佳選擇。 安裝(和管理多個版本)Java SDK的最簡單方法是使用SDKMAN!
了解如何使用SDKMAN管理多個Java SDK! 輕松
要支持本機映像,請確保安裝所有必需的依賴項。 可以在GraalVM文檔中找到更多信息: https ://www.graalvm.org/docs/reference-manual/native-image/
GraalVM官方文檔: GraalVM
終奌站
該服務是使用iTerm2和oh-my-zsh在macOS上開發的。 我還將httpie用作默認的HTTP客戶端。
IntelliJ
我首選的IDE是IntelliJ,我在從事此項目時就使用了它。
在本文中了解有關我在macOS上使用的工具的更多信息: macOS:(Java)開發人員的基本工具
使用Docker運行PostgreSQL
該應用程序將連接到Postgres服務器,并根據配置文件( dev , test , prod )應用不同的配置。 為此,我們將需要運行三臺服務器:每臺服務器具有不同的數據庫名稱,端口和憑據。 為了簡化設置,可以使用Docker。
開發數據庫
- 創建并運行容器:
- 運行先前停止的容器:
測試數據庫
- 創建并運行容器:
- 運行先前停止的容器:
產品數據庫
- 創建并運行容器:
- 運行先前停止的容器:
入門
引導應用程序
您可以在命令行中使用Maven引導應用程序,也可以使用在線生成器。 在線生成器允許探索可以構成Quarkus應用程序的擴展和技術,并且不需要本地Maven安裝。 您可以在此處訪問生成器: https : //code.quarkus.io
需要以下擴展來構建PetClinic API服務:
- RESTEasy JAX-RS –實現JAX-RS等的REST框架
- RESTEasy Jackson –對RESTEasy的Jackson序列化支持
- SmallRye OpenAPI –使用OpenAPI記錄您的REST API – Swagger UI隨附
- 帶有Panache的Hibernate ORM –在帶有Panache的Hibernate ORM中定義持久性模型
- Hibernate Validator –驗證進入您的REST端點的數據
- JDBC驅動程序– PostgreSQL – PostgreSQL數據庫連接器
- Flyway –處理數據庫架構遷移
選擇依賴項后,您可以下載zip,解壓縮并開始開發服務。
下載的項目具有標準的Maven項目布局。 它包含Maven包裝器,因此不需要本地Maven安裝即可開發項目。 您還將注意到src/main/docker與本地和JVM映像的Docker文件一起。
主要配置文件application.properties位于src/main/resources 。 此文件夾還包含META-INF/resources文件夾,用于存儲應用程序的靜態資源,例如index.html文件。
在
在線生成器默認情況下使用Java 8生成項目,因此,要使用Java 11,需要進行一些調整。
- 在生成的項目的pom.xml中,更改Java版本:
- 在src/main/docker/Dockerfile.jvm設置ARG JAVA_PACKAGE=java-11-openjdk-headless
在開發模式下運行項目
進行更改后,您可以啟動應用程序。 打開終端,導航到項目的文件夾并運行以下命令:
$ ./mvnw compile quarkus:dev注意:Quarkus具有三種內置模式: dev , test和prod取決于您如何運行應用程序。
在IntelliJ中開發
在IntelliJ中,您只需打開項目的文件夾或pom.xml 。 ( File > Open )。 該項目只能使用Maven啟動。 這可以通過Maven運行配置來完成,因為沒有主類可以啟動應用程序,例如在Spring Boot中 。
對我來說,使用Quarkus進行開發時最好的體驗是在IntelliJ外部的終端中運行應用程序時。
調試
當以開發模式執行Quarkus應用程序時,它將以啟用的調試協議(在端口5005上)啟動。 要在IntelliJ中調試Quarkus應用程序,您需要通過Run > Attach to Process調試器附加到正在Run > Attach to Process 。 我沒有調試應用程序的麻煩。
注意:可以在禁用調試的開發模式下運行該應用程序: ./mvnw quarkus:dev -Ddebug=false ,但老實說,默認情況下啟用調試器時,我沒有發現任何性能問題。
實時重載
我認為,實時重新加載是Quarkus最強大的功能。 效果驚人。 基本上,您可以更改源代碼中所需的任何內容,執行請求,然后眨眼間即可重新加載應用程序。 我正在重新整理類和程序包,移動文件,添加和刪除端點,而所有這些操作都沒有一次重啟。
數據源配置
所有屬性都轉到src/main/resources/application.properties 。
默認數據源屬性(
quarkus.datasource.url=jdbc:postgresql: //localhost:5432/petclinic quarkus.datasource.driver=org.postgresql.Driver quarkus.datasource.username=petclinic quarkus.datasource.password=petclinicDev數據源屬性(
要設置模式(或配置文件)的特定屬性,請使用%mode :
%dev.quarkus.datasource.url=jdbc:postgresql: //localhost:5433/petclinic-dev %dev.quarkus.datasource.username=petclinic-dev %dev.quarkus.datasource.password=petclinic-dev測試數據源屬性(
%test.quarkus.datasource.url=jdbc:postgresql: //localhost:5434/petclinic-test %test.quarkus.datasource.username=petclinic-test %test.quarkus.datasource.password=petclinic-test另請參閱: https : //quarkus.io/guides/datasource
飛路遷移
要使用Flyway,請在src/main/resources創建db/migration文件夾,然后添加遷移文件。 我的第一個遷移文件稱為V1.0.0__PetClinic.sql ,其中包含該服務的所有架構(DDL)和示例數據。
注意:Quarkus支持可以通過quarkus.hibernate-orm.sql-load-script為每個配置文件配置的SQL導入,但是我無法使其工作。 請參閱我在Github上報告的問題: https : //github.com/quarkusio/quarkus/issues/7358
另請參閱: https : //quarkus.io/guides/flyway
JPA實體
PetClinic的域模型相對簡單,但是它包含一些單向和雙向關聯以及基本繼承,這使其比簡單的Hello World類型的模型要好一些。
請注意,在此示例中,JPA實體由相應的Panache存儲庫直接在JAX-RS資源中返回(請參見下文),因此,實體類包含JPA和Jackson批注的混合。
例如:
@Entity @Table (name = "visits" ) public class Visit extends BaseEntity { @Column (name = "visit_date" ) @JsonFormat (pattern = "yyyy/MM/dd HH:mm" ) private LocalDateTime date; @NotEmpty @Column (name = "description" ) private String description; @ManyToOne @JoinColumn (name = "pet_id" ) private Pet pet; @ManyToOne @JoinColumn (name = "vet_id" ) private Vet vet; public Visit() { this .date = LocalDateTime.now(); } } @Entity @Table (name = "vets" , uniqueConstraints = @UniqueConstraint (columnNames = { "first_name" , "last_name" }) ) public class Vet extends Person { @ManyToMany (fetch = FetchType.EAGER) @JoinTable (name = "vet_specialties" , joinColumns = @JoinColumn (name = "vet_id" ), inverseJoinColumns = @JoinColumn (name = "specialty_id" )) @JsonIgnore private Set<Specialty> specialties; @OneToMany (cascade = CascadeType.ALL, mappedBy = "vet" , fetch = FetchType.EAGER) @JsonIgnore private Set<Visit> visits; }所有實體都位于pl.codeleak.samples.petclinic.model包中。
休眠ORM與Panache
如果您熟悉Spring,我想您已經聽說過Spring Data項目。 在我看來, 帶有Panache的Hibernate ORM具有類似的目標:通過消除重復和繁瑣的工作,簡化了JPA的開發。 Panache支持排序,分頁, java.util.Optional和java.utitl.stream.Stream等。
你有兩種方法來工作,以耀目:與創建實體PanacheEntity或創建庫PanacheRepository 。 我在這個項目中嘗試了兩種方法,但是由于實體中的繼承問題,我決定采用老式方法。
Hibernate ORM和Panache的基本存儲庫定義:
public class OwnerRepository implements PanacheRepository<Owner> { List<Owner> findByLastName(String lastName) { return list( "lastName" , lastName); } }所有存儲庫都位于pl.codeleak.samples.petclinic.repository包中。
另請參閱: https : //quarkus.io/guides/hibernate-orm-panache
創建REST API
JAX-RS資源
Quarkus將JAX-RS與RESTEasy結合使用。 要創建API端點,我們需要創建JAX-RS資源:
@Path (OwnerResource.RESOURCE_PATH) @Produces (MediaType.APPLICATION_JSON) public class OwnerResource { public static final String RESOURCE_PATH = "/owners" ; @Context UriInfo uriInfo; @Inject OwnerRepository ownerRepository; @Inject PetRepository petRepository; @GET public Response getAll( @BeanParam PageRequest pageRequest) { ????????} @GET @Path ( "{id}" ) public Response getOne( @PathParam ( "id" ) Long id) { } @GET @Path ( "{id}/pets" ) public List<Pet> getPets( @PathParam ( "id" ) Long id) { ????} @POST @Consumes (MediaType.APPLICATION_JSON) @Transactional public Response create( @Valid Owner owner) { ????} }依賴注入是通過CDI完成的–上下文和依賴注入 。 資源對象將由Quarkus自動配置。 必須將所有其他依賴項配置為具有CDI批注的依賴項注入。
例如,可以使用@ApplicationScoped注釋存儲庫,然后使用@Inject注入存儲庫:
@ApplicationScoped public class OwnerRepository implements PanacheRepository<Owner> { List<Owner> findByLastName(String lastName) { return list( "lastName" , lastName); } } @ApplicationScoped public class PetRepository implements PanacheRepository<Pet> { }所有資源都位于pl.codeleak.samples.petclinic.api包中。
另請參閱: https : //quarkus.io/guides/cdi-reference
分頁
如前所述,Panache為分頁結果提供支持。 我們可以輕松地在我們的資源中輕松利用它:
@GET public Response getAll( @BeanParam PageRequest pageRequest) { return Response.ok(((PanacheRepository) petRepository).findAll() .page(Page.of(pageRequest.getPageNum(), pageRequest.getPageSize())) .list()).build(); }PageRequest是一個包含pageNum和pageSize查詢參數的bean:
public class PageRequest { @QueryParam ( "pageNum" ) @DefaultValue ( "0" ) private int pageNum; @QueryParam ( "pageSize" ) @DefaultValue ( "10" ) private int pageSize; }使用httpie可以輕松完成執行分頁的請求:
$ http get : 8080 /owners pageNum== 0 pageSize== 2 HTTP/ 1.1 200 OK Content-Length: 250 Content-Type: application/json [ { "address" : "110 W. Liberty St." , "city" : "Madison" , "firstName" : "George" , "id" : 1 , "lastName" : "Franklin" , "telephone" : "6085551023" }, { "address" : "638 Cardinal Ave." , "city" : "Sun Prairie" , "firstName" : "Betty" , "id" : 2 , "lastName" : "Davis" , "telephone" : "6085551749" } ]交易次數
在JPA中創建新對象需要活動事務。 為了將事務綁定到資源對象中的當前方法,請使用@Transactional ,否則在方法執行期間將引發異常:
@POST @Consumes (MediaType.APPLICATION_JSON) @Transactional public Response create( @Valid Owner owner) { ownerRepository.persist(owner); var location = uriInfo.getAbsolutePathBuilder() .path( "{id}" ) .resolveTemplate( "id" , owner.getId()) .build(); return Response.created(location).build(); }使用httpie創建新資源:
$ http post : 8080 /owners <<< ' { "address" : "110 W. Liberty St." , "city" : "Madison" , "firstName" : "George" , "lastName" : "Franklin" , "telephone" : "6085551023" }' HTTP/ 1.1 201 Created Content-Length: 0 Location: http: //localhost:8080/owners/1042驗證方式
該項目使用Hibernate Validator擴展。 使用此擴展,您可以使用標準的Hibernate驗證注釋(例如@NotBlank ),并且當資源方法的輸入參數使用@Valid注釋時,驗證將自動觸發,并且錯誤響應將返回給調用該方法的客戶端。
以下請求的示例響應:
$ http post : 8080 /owners <<< '{}' HTTP/ 1.1 400 Bad Request Content-Length: 626 Content-Type: application/json validation-exception: true { "classViolations" : [], "exception" : null , "parameterViolations" : [ { "constraintType" : "PARAMETER" , "message" : "must not be empty" , "path" : "create.owner.address" , "value" : "" }, ????????... { "constraintType" : "PARAMETER" , "message" : "must not be empty" , "path" : "create.owner.telephone" , "value" : "" } ], "propertyViolations" : [], "returnValueViolations" : [] }關于實時重新加載功能的注意事項:您可以對源代碼進行任何更改,并使用httpie執行新請求。 該應用程序快速重新加載,您會立即獲得結果。 無需重新啟動。
另請參閱: https : //quarkus.io/guides/validation
Java 8日期和時間支持
RESTEasy Jackson擴展位于項目中時,在JSON序列化和反序列化期間支持java.util.time類型。
在以下示例中,訪問日期以@JsonFormat批注提供的格式進行序列化和反序列化:
@Entity @Table (name = "visits" ) public class Visit extends BaseEntity { @Column (name = "visit_date" ) @JsonFormat (pattern = "yyyy/MM/dd HH:mm" ) private LocalDateTime date; }檢查如何使用htppie序列化日期:
$ http get : 8080 /visits/ 1 HTTP/ 1.1 200 OK Content-Length: 174 Content-Type: application/json { "date" : "2013/01/01 00:00" , "description" : "rabies shot" , "id" : 1 , "pet" : { "birthDate" : "2012/09/04" , "id" : 7 , "name" : "Samantha" }, "vet" : { "firstName" : "Helen" , "id" : 2 , "lastName" : "Leary" } }您還可以使用所需的日期時間格式將訪問存儲在請求正文中:
$ http post : 8080 /visits <<< ' { "date" : "2020/01/01 00:00" , "description" : "lorem ipsum" , "pet" : { "id" : 7 }, "vet" : { "id" : 2 } }' HTTP/ 1.1 201 Created Content-Length: 0 Location: http: //localhost:8080/visits/1042OpenAPI / Swagger支持
SmallRye OpenAPI擴展負責提供API文檔,并且在開發模式下啟用了SwaggerUI。
默認端點是:
- OpenAPI文檔– /openapi
- SwaggerUI – /swaggerui
另請參閱: https : //quarkus.io/guides/openapi-swaggerui
整合測試
Quarkus使用JUnit 5和RESTAssured進行集成測試。 可以使用@QuarkusTest批注創建test ,并且默認情況下會在激活test配置文件的情況下執行test 。
@QuarkusTest public class PetResourceTest { @Test public void pagedList() { given() .when().get( "/pets?pageNum=0&pageSize=2" ) .then() .statusCode( 200 ) .body( "$.size()" , is( 2 ), "name" , containsInAnyOrder( "Leo" , "Basil" ) ); } }Quarkus測試要求應用程序正在運行。 通過使用CDI @Alternate beans定義,可以替換測試中的選定bean。 備用bean必須放置在src/test/java 。
注意:由于有了配置文件支持,您可以使用單獨的數據庫容器輕松配置test配置文件的數據源。 請參閱測試數據源屬性 。
另請參閱: https : //quarkus.io/guides/getting-started-testing
打包并運行應用程序
該應用程序可以打包為./mvnw package 。
它在/target目錄中生成可執行文件quarkus-petclinic-api-1.0.0-runner.jar文件,并將依賴項復制到target/lib目錄中。
[INFO] [io.quarkus.deployment.pkg.steps.JarResultBuildStep] Building thin jar: /Users/rafal.borowiec/Projects/quarkus/quarkus-petclinic-api/target/quarkus-petclinic-api- 1.0 . 0 -runner.jar [INFO] [io.quarkus.deployment.QuarkusAugmentor] Quarkus augmentation completed in 1888ms [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 15.868 s [INFO] Finished at: 2020 - 02 -23T19: 18 : 25 + 01 : 00 [INFO] ------------------------------------------------------------------------現在可以使用java -jar target/quarkus-petclinic-api-1.0.0-runner.jar運行該應用程序。
2020 - 02 - 23 19 : 19 : 10 , 169 INFO [io.quarkus] (main) quarkus-petclinic-api 1.0 . 0 (running on Quarkus 1.2 . 1 .Final) started in 2 .011s. Listening on: http: .011s. Listening on: http: //0.0.0.0:8080 .011s. Listening on: http: //0.0.0.0:8080 2020 - 02 - 23 19 : 19 : 10 , 171 INFO [io.quarkus] (main) Profile prod activated. 2020 - 02 - 23 19 : 19 : 10 , 171 INFO [io.quarkus] (main) Installed features: [agroal, cdi, flyway, hibernate-orm, hibernate-orm-panache, hibernate-validator, jdbc-postgresql, narayana-jta, rest-client, resteasy, resteasy-jackson, smallrye-openapi]注意: uber-jar可以與./mvnw clean package -DskipTests=true -Dquarkus.package.uber-jar=true一起打包。
創建以JVM模式運行應用程序的Docker容器
$ ./mvnw clean package $ docker build -f src/main/docker/Dockerfile.jvm -t quarkus/petclinic-api-jvm . Successfully built 1a5d963fedfa Successfully tagged quarkus/petclinic-api-jvm:latest使用鏈接運行容器,執行Postgres數據庫容器,并使用環境變量覆蓋數據源url:
$ docker run -i --rm -p 8080 : 8080 --link petclinic-db -e QUARKUS_DATASOURCE_URL= 'jdbc:postgresql://petclinic-db/petclinic' quarkus/petclinic-api-jvm 2020 - 02 - 23 20 : 39 : 18 , 949 INFO [io.quarkus] (main) quarkus-petclinic-api 1.0 . 0 (running on Quarkus 1.2 . 1 .Final) started in 3 .475s. Listening on: http: .475s. Listening on: http: //0.0.0.0:8080 .475s. Listening on: http: //0.0.0.0:8080 2020 - 02 - 23 20 : 39 : 18 , 949 INFO [io.quarkus] (main) Profile prod activated. 2020 - 02 - 23 20 : 39 : 18 , 949 INFO [io.quarkus] (main) Installed features: [agroal, cdi, flyway, hibernate-orm, hibernate-orm-panache, hibernate-validator, jdbc-postgresql, narayana-jta, rest-client, resteasy, resteasy-jackson, smallrye-openapi注意: petclinic-db是在此處創建的Postgres容器的名稱: Prod database 。 我們還需要傳遞數據源URL。 閱讀有關在運行時覆蓋配置屬性的更多信息:在運行時覆蓋屬性
創建本機可執行文件
您可以使用以下命令創建本機可執行文件:
$ ./mvnw package -Pnative [INFO] [io.quarkus.deployment.pkg.steps.NativeImageBuildStep] Building image from /Users/rafal.borowiec/Projects/quarkus/quarkus-petclinic-api/target/quarkus-petclinic-api- 1.0 [INFO] [io.quarkus.deployment.pkg.steps.NativeImageBuildStep] Building native image from /Users/rafal.borowiec/Projects/quarkus/quarkus-petclinic-api/target/quarkus-petclinic-api- . 0 - native -image-source-jar/quarkus-petclinic-api- 1.0 . 0 -runner.jar ... [quarkus-petclinic-api- 1.0 . 0 -runner: 50503 ] (typeflow): 72 , 535.72 ms [quarkus-petclinic-api- 1.0 . 0 -runner: 50503 ] (objects): 49 , 325.68 ms [quarkus-petclinic-api- 1.0 . 0 -runner: 50503 ] (features): 3 , 115.04 ms [quarkus-petclinic-api- 1.0 . 0 -runner: 50503 ] analysis: 135 , 220.10 ms [quarkus-petclinic-api- 1.0 . 0 -runner: 50503 ] (clinit): 1 , 966.77 ms [quarkus-petclinic-api- 1.0 . 0 -runner: 50503 ] universe: 6 , 919.51 ms [quarkus-petclinic-api- 1.0 . 0 -runner: 50503 ] (parse): 13 , 679.33 ms [quarkus-petclinic-api- 1.0 . 0 -runner: 50503 ] (inline): 18 , 193.40 ms [quarkus-petclinic-api- 1.0 . 0 -runner: 50503 ] (compile): 70 , 849.75 ms [quarkus-petclinic-api- 1.0 . 0 -runner: 50503 ] compile: 111 , 062.75 ms [quarkus-petclinic-api- 1.0 . 0 -runner: 50503 ] image: 8 , 843.46 ms [quarkus-petclinic-api- 1.0 . 0 -runner: 50503 ] write: 1 , 789.58 ms [quarkus-petclinic-api- 1.0 . 0 -runner: 50503 ] [total]: 282 , 727.03 ms [INFO] [io.quarkus.deployment.QuarkusAugmentor] Quarkus augmentation completed in 287304ms [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS [INFO] ------------------------------------------------------------------------ [INFO] Total time: 04 : 58 min [INFO] Finished at: 2020 - 02 -23T19: 25 : 10 + 01 : 00 [INFO] ------------------------------------------------------------------------創建本機可執行文件的過程需要花費一些時間,但是值得等待它完成以查看應用程序的啟動時間:
$ ./target/quarkus-petclinic-api- 1.0 . 0 -runner 2020 - 02 - 23 19 : 26 : 03 , 959 INFO [io.quarkus] (main) quarkus-petclinic-api 1.0 . 0 (running on Quarkus 1.2 . 1 .Final) started in 0 .066s. Listening on: http: .066s. Listening on: http: //0.0.0.0:8080 .066s. Listening on: http: //0.0.0.0:8080 2020 - 02 - 23 19 : 26 : 03 , 959 INFO [io.quarkus] (main) Profile prod activated. 2020 - 02 - 23 19 : 26 : 03 , 959 INFO [io.quarkus] (main) Installed features: [agroal, cdi, flyway, hibernate-orm, hibernate-orm-panache, hibernate-validator, jdbc-postgresql, narayana-jta, rest-client, resteasy, resteasy-jackson, smallrye-openapi]本機可執行文件啟動為0.67秒,而JVM版本為2秒。
創建一個以純模式運行應用程序的Docker容器
默認情況下,本機可執行文件以操作系統支持的格式創建。 由于容器使用的可執行文件格式可能與操作系統生成的格式不同,因此Maven構建可以從容器內部生成可執行文件:
$ ./mvnw package -Pnative -Dquarkus. native .container-build= true要調整構建器映像的版本,您需要設置quarkus.native.builder-image屬性:
$ ./mvnw clean package -Pnative -DskipTests= true -Dquarkus. native .container-build= true -Dquarkus. native .builder-image=quay.io/quarkus/ubi-quarkus- native -image: 20.0 . 0 -java11現在,構建并運行容器:
$ docker build -f src/main/docker/Dockerfile. native -t quarkus/petclinic-api . $ docker run -i --rm -p 8080 : 8080 quarkus/petclinic-api注意:有關構建本機可執行文件的更多信息,請參見Quarkus文檔: https ://quarkus.io/guides/building-native-image
源代碼
可以在Github上找到本文的源代碼: https : //github.com/kolorobot/quarkus-petclinic-api
翻譯自: https://www.javacodegeeks.com/2020/02/getting-started-with-quarkus.html
總結
- 上一篇: 绿色的衣服配什么颜色的裤子好看 绿色的衣
- 下一篇: 参数化测试 junit_JUnit中的参