+4

Một số kỹ thuật cơ bản sử dụng trong Maven Project

Trong phần này mình sẽ giới thiệu một số kỹ thuật cơ bản sử dụng trong Maven Project:

  • Build automation.
  • Project modularization.
  • Dependency management.
  • Sourece code quality checks.
  • Test driven development.
  • Acceptance testing automation.

Build automation.

Build automation là kịch bản các công việc mà một người phát triển phần mền làm cơ bản hàng ngày, các công việc đó bao gồm:

  • Compile source code thành binary code.
  • Đóng gói(Package) source code đã được chuyển thành binary.
  • Chạy các test case.
  • Triển khai lên hệ thống remote.
  • Tạo tài liệu và các chú thích release.

Build automation cùng cấp nhiều lời ích bao gồm tăng tốc động build, loại bỏ những bản build không đạt chất lượng, chuẩn hóa việc tổ chức, tăng cường năng xuất, và thiện chất lượng sản phẩm. Ngày nay nó được coi như là một phần cần thiết của một developer.

Để bắt đầu bạn tạo một simple project Maven bằng cách sử dụng dòng lệnh sau trong comand line

$ mvn archetype:generate -DgroupId=org.example.maven -DartifactId=MySampleApp

archetype:generate là dòng lệnh sẽ tạo một Maven project đơn giản cho chúng ta, nếu như bạn chọn maven-archetype-quickstart từ danh sách thì project của chúng ta sẽ có cấu trúc như sau:

.
├── pom.xml
└── src
    ├── main
    │   └── java
    │       └── org
    │           └── example
    │               └── maven
    │                   └── App.java
    └── test
        └── java
            └── org
                └── example
                    └── maven
                        └── AppTest.java

Bạn chỉ cần thực hiện một vài phase trong build life cycle Maven sẽ cho pehps bạn tự đông chạy tất cả phase đúng theo trình tự. Chỉ cần chạy lệnh mvn install, và nó sẽ bao gồm các build lifecycle mặc định bao gồm compiling, testing,packaging, và installingartifact trong local repository.

Mọi Maven project bất kiểu package nào thì build lifecycle mặc định sẽ được áp dụng và build sẽ được tự động. Build lifecycle mặc định sẽ thực hiện các phase sau:

  • Validate: validate tất cả các thông tin của project có tồn tại và đúng hay không.
  • Compile: compile soure code.
  • Test: chạy các case unit test tương ứng với frame work sử dụng.
  • Package: đóng gói code đã được compile theo đúng định dạng.
  • Integration-test: thực hiện package trong môi trường integration test.
  • Verify: kiểm tra package có hợp lệ hay không.
  • Install: Install packege vào local repository.
  • Deploy: Install package lên remote repository.

Mỗi một phase là một Mave plugin, khi chúng ta thực hiện chúng trong lần đầu tiên, Maven sẽ sẽ download plugin từ Maven Central Repostiory online có tìm thấy tại http:// repo1.maven.org/maven2 và sẽ cài đặt trong local Apache Mave repository của bạn.

Project modularization.

Khi bạn xậy dựng một Enterprise Application lớn, nó cần thiết phải tương tác với một database, làm việc với các service, cung cấp một mô hình web và thiết bị cung cấp cho user, expose các API cho các hệ thống khác sử dụng, Đồng thời việc module hóa cũng chia một project lớn thành những project con hoặc các module.

Maven cung cấp hoàn hảo việc hỗ trợ để tổ chức thông qua Maven Multi-modular projects. Multi-modular project bao gồm một Parent project chứa các Child Project hoặc Module. File pom của Parent Project chứa các tham chiếu tới các sub-module, mỗi module có thể có các kiểu khác nhau tương ứng với loại package được định nghĩa trong mỗi file pom. Để tạo một Parent project bạn định nghĩa một file pom tương tự dưới đây, nhưng phải đảm bảo thiết lập cho packaging là pom:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.example.maven</groupId>
  <artifactId>TestMavenModular</artifactId>
  <version>1.0-SNAPSHOT</version>
  <packaging>pom</packaging>
  <name>ExampleMavenModular</name>
</project>

Đây là một file parent pom cơ bản của project ExampleMavenModular và nó chưa chứa bất kỳ một sub module nào, để tạo một sub module đầu tiên, chúng ta sử dụng comand line trong thư mục chứa file pom.

mvn archetype:generate

Bạn điền đầy đủ các thông tin groupId, atifactId, package, version, chú ý ở đây bạn nhập thông tin groupId giống với Parent project Ví dụ ở mình chọn một Java Project có archetypes là maven-archetype-quickstart.

Sau khi generate project thành công bạn kiểm tra file pom của parent project bạn sẽ thấy một đoạn định nghĩa child module được thêm vào.

<modules>
    <module>moduleJar</module>
 </modules>

Sub module đã được chúng ta tự động add vào parent POM và bây giờ chúng ta sẽ tạo thêm một sub module khác lần này sẽ là một Maven web application bằng command line sau.

$ mvn archetype:generate -DarchetypeArtifactId=maven-archetype-webapp

Bây giờ bạn kiểm tra parent POM file, chúng ta sẽ thấy cả hai sub module được thêm vào.

<modules>
    <module>moduleJar</module>
    <module>moduleWar</module>
</modules>

Chúng ta kiểm tra cấu trúc thư mục sẽ thấy như sau:

└── ExampleMavenModular
    ├── moduleJar
    │   ├── pom.xml
    │   └── src
    │       ├── main
    │       │   └── java
    │       │       └── org
    │       │           └── example
    │       │               └── maven
    │       │                   └── App.java
    │       └── test
    │           └── java
    │               └── org
    │                   └── example
    │                       └── maven
    │                           └── AppTest.java
    ├── moduleWar
    │   ├── pom.xml
    │   └── src
    │       └── main
    │           ├── resources
    │           └── webapp
    │               ├── WEB-INF
    │               │   └── web.xml
    │               └── index.jsp
    └── pom.xml

Để comple cũng như install tất cả sub module chúng ta chỉ cần thực hiện comand line tại parent POM folder:

$ mvn clean install

Thực hiện một build phase trong parent project sẽ tự động thực hiện tất cả các child project theo đúng thứ tự.

[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO]
[INFO] ExampleMavenModular ................................ SUCCESS [  0.573 s]
[INFO] moduleJar .......................................... SUCCESS [  4.230 s]
[INFO] moduleWar Maven Webapp ............................. SUCCESS [  0.720 s]
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 5.628 s
[INFO] Finished at: 2017-01-08T10:35:02+07:00
[INFO] Final Memory: 20M/206M
[INFO] ------------------------------------------------------------------------

Dependency management

Maven dependeny có tất cả 6 scope:

  • Compile: Đây là default scope. Compile dependency sẽ tồn tại trong classpaths.
  • Provided: Đây là scope cho phép JDK hoặc môi trường cung cấp các dependency trong thời gian runtime.
  • Runtime: Các dependency được yêu cầu lúc runtime và được chỉ định trong runtime classpath.
  • Test: các Dependency được yêu cầu khi copile và excute test.
  • System: Tương tự như Provided nhưng bạn phải cung cấp file JAR một cách rõ ràng.
  • Import: import các dependency được chỉ định trong POM thông qua <dependencyManagement/>

Các dependency cho một Maven project được chỉ đình file POM.

<dependencies>
       <dependency>
         <groupId>...</groupId>
         <artifactId>...</artifactId>
         <version>...</version>
         <scope>...</scope>
       </dependency>
</dependencies>

Trong Multi-modular project, các dependency có thể được định nghĩa trong parent POM file và có thể được kế thừa bởi các child POM file khi cần thiết. Ví dụ dưới đây một Multi modular project có một MySql dependency, Parent POM đã chứa toàn bộ định nghĩa của dependency này

<dependencyManagement>
     <dependencies>
       <dependency>
         <groupId>mysql</groupId>
         <artifactId>mysql-connector-java</artifactId>
         <version>5.1.2</version>
       </dependency>
     <dependencies>
</dependencyManagement>

Tất cả các child module yêu cầu MySQL sẽ chỉ cần include một dependency definition cơ bản như sau:

<dependency>
     <groupId>mysql</groupId>
     <artifactId>mysql-connector-java</artifactId>
</dependency>

Các dependency có scope và tye mặc định là compile và JAR. Tuy nhiên chúng cho thể overridden khi cần thiết

<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.8.2</version>
  <scope>test</scope>
</dependency>
 
<dependency>
  <groupId>...</groupId>
  <artifactId>...</artifactId>
  <version>...</version>
  <type>war</type>
</dependency>

Đặc biệt System dependency sẽ không tìm thấy trong repository, do vậy chúng ta cần chỉ định đường dẫn cụ thể

<dependencies>
     <dependency>
       <groupId>sun.jdk</groupId>
       <artifactId>tools</artifactId>
       <version>1.5.0</version>
       <scope>system</scope>
       <systemPath>${java.home}/../lib/tools.jar</systemPath>
     </dependency>
</dependencies>

Source code quality checks

Việc kiểm tra và xác nhận chất lượng source code đảm application được thiết kế đúng và nó còn giúp những người programmer ít kinh nghiệm tuân theo chuẩn các chuẩn coding.

Apache Maven PMD plugin cho phép chúng ta phân tích source và tạo report tương ứng. Trong một cấu hình tiêu chuẩn thì quá trình build Mave Project sẽ thất bại nếu như PMD tìm thấy issue trong source code.

PMD giới thiệu 4 goal:

  • pmd:pmd tạo một PMD site report dựa trên các rulesets được cấu hình trong plugin.
  • pmd:cpdtạo ra một report cho công cụ PMD's Copy/Paste Detector (CPD) .
  • pmd:check xác thực PMD report có tồn tại hay không.
  • pmd:pcd-check xác thực CPD có tồn tại hay không.

Để sử dụng PMD sau khi chúng ta tạo ra một Maven project chúng ta sẽ thêm PMD plugin trong file pom trong thẻ reporting

<reporting>
       <plugins>
         <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-pmd-plugin</artifactId>
          <version>3.7</version>
       </plugin>
       </plugins>
</reporting>

Với cấu hình như này bạn có thể sử dụng PMD với các ruleset mặc định, dưới đây là cấu hình cho phép bạn custom các rules cũng như cấu hình cho việc kiểm tra chất lượng code.

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-pmd-plugin</artifactId>
  <version>2.5</version>
  <configuration>
       <rulesets>
             <ruleset>/rulesets/basic.xml</ruleset>
             <ruleset>/rulesets/controversial.xml</ruleset>
             <ruleset>http://localhost/design.xml</ruleset>
        </rulesets>
        <sourceEncoding>utf-8</sourceEncoding>
        <minimumTokens>100</minimumTokens>
       <targetJdk>1.6</targetJdk>
    </configuration>
</plugin>

Để thực hiện kiểm tra bằng PMD chúng ta di chuyển tới project POM folder, và thực hiện command line sau:

mvc pmd:pmd

PMD cũng có thể tích hợp vào lifecycle mặc định của Maven, bằng cách như sau:

<build>
       <plugins>
       <plugin>
         <groupId>org.apache.maven.plugins</groupId>
         <artifactId>maven-pmd-plugin</artifactId>
         <version>2.5</version>
         <executions>
           <execution>
           <goals>
             <goal>check</goal>
           <goal>cpd-check</goal>
           </goals>
         </execution>
         </executions>
       </plugin>
       </plugins>
</build>

PMD là một open source tool có thể scan java code và tạo các code quality report. Các report này được tạo ra dựa trên việc xác định các khả năng bug, dead code, non-optimized code, duplicate code …

Test Driven Development

Test Driven Development hoặc TDD và cũng được biết đến rộng rãi, việc lặp đi lặp lại vòng đời pahts triển trong đó lập trình viên đầu tiên viết một test case fail sau đó xây dựng chức năng tiếp tục refactor code nếu cần thiết.

Maven thực hiện unit test và tích hợp unit test như một phần của build lifecycle, nó cho phép người lập trình viên cũng như team dễ dàng cài đặt và thực hiện TDD.

Chúng ta sẽ sử dụng một framework được sử dụng phổ biến nhất là JUnit để tạo một unit test.

<dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
</dependencies>

Nếu như sử dụng maven-archetype-quickstart archetype để tạo một Maven project nó sẽ mặc định chứa một JUnit dependency và các sample test case, tuy nhiên bạn nên upgrade version JUnit được sử dụng vì mặc định version được sử dụng là 3.8.1.

Các test case sẽ nằm trong thư mục <project_base_dir>/src/test/java. Bạn có thể sử dụng các IDE như Eclipse, NetBeans, Intellij các IDE này sẽ hỗ trợ JUnit và Maven giúp bạn tạo các test case nhanh hơn.

public class MyClassTest {
    @Test
    public void testMultiply() {
        MyClass tester = new MyClass();
        assertEquals("Result", 50, tester.multiply(10, 5));
    }
}

nếu bạn muốn merge các test case, chúng ta có thể gom chúng lại thành một test suite:

@RunWith(Suite.class)
@Suite.SuiteClasses( { MyClassTest.class })
public class AllTests {
}

Để thực hiện chạy unit test với Maven chúng ta có thể sử dụng command line sau để thực hiện test phase.

$ mvn test

Ngoài ra test phase sẽ được chạy tự động mặc định trong build lifecycle mặc định, vì thế khi thực hiện install phase, thì test phase cũng sẽ tự động được chạy.

$mvn install

Maven sẽ hiển thị kết quả test trên console, bạn sẽ thấy tương tự như này.

-------------------------------------------------------
 T E S T S
-------------------------------------------------------
Running com.maven.exaple.AppTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.034 sec
Running com.maven.exaple.MyClassTest
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.029 sec

Results :

Tests run: 2, Failures: 0, Errors: 0, Skipped: 0

Maven Surefire plugin có một test goal bị rằng buộc với test phase trong build lifecycle. nó sẽ thực hiện mọi test case trong folder <project_base_dir>/src/test/java với các filename tương ứng với các pattern sau:

  • **/Test*.java
  • **/*Test.java
  • **/*TestCase.java

Nếu như có một hoặc nhều test case fail, thì build phase sẽ thất bại. Kết quả sẽ được hiển thị ra consele và một phiên bản XML sẽ được tìm thấy trong folder <project_base_dir>/target/surefire-reports.

Accept testing automation.

Selenium là một framework automation testing phổ biến nó có thể làm việc với nhiều ngôn ngữ khác nhau bao gồm java, C#, Ruby, Groovy, Python, PHP, Perl.

Để viết automation test, Selenium cung cấp Selenium IDE, nó là một plugin Mozilla Firefox cho phép chúng ta theo rõi và kiểm tra các test case cho các ngôn ngữ khác nhau trong đó bao gồm Java.

Selenium Maven Plugin cho phép bạn chỉ định các automation test case được tạo cho Selenium trong Maven project của bạn và tích hợp chúng với Maven build lifecycle.

Đầu tiên chúng ta tạo một web aplication bằng comman line sau:

$ mvn archetype:generate -DgroupId=com.maven.example
-DartifactId=MySampleWebApp -DarchetypeArtifactId=maven-archetype-webapp

Thêm các dependency JUnit và Selenium

<dependencies>
   <dependency>
       <groupId>junit</groupId>
       <artifactId>junit</artifactId>
       <version>4.8.2</version>
       <scope>test</scope>
   </dependency>
   <dependency>
       <groupId>org.codehaus.mojo</groupId>
       <artifactId>selenium-maven-plugin</artifactId>
       <version>2.3</version>
       <scope>test</scope>
   </dependency>
</dependencies>

Để khởi động Selenium server nó cần phải được đồng bộ hóa với pre-integration test phase của build lifecycle.

<plugins>
       <plugin>
         <groupId>org.codehaus.mojo</groupId>
         <artifactId>selenium-maven-plugin</artifactId>
         <executions>
           <execution>
             <phase>pre-integration-test</phase>
             <goals>
               <goal>start-server</goal>
             </goals>
             <configuration>
               <background>true</background>
             </configuration>
           </execution>
         </executions>
       </plugin>
</plugins>

Cấu hình trên cho phép khởi động Selenium server trước khi thực hiện integration test.

Tuy nhiên để chạy các test case Selenium, chúng ta cần phải start web application server, Mave Jetty plugin cho phép chúng thực hiện điều này.

<plugin>
  <groupId>org.mortbay.jetty</groupId>
  <artifactId>jetty-maven-plugin</artifactId>
  <version>8.1.16.v20140903</version>
  <executions>
    <execution>
      <id>start-jetty</id>
      <phase>pre-integration-test</phase>
      <goals>
        <goal>run</goal>
      </goals>
      <configuration>
        <scanIntervalSeconds>0</scanIntervalSeconds>
        <daemon>true</daemon>
      </configuration>
    </execution>
    <execution>
    <id>stop-jetty</id>
         <phase>post-integration-test</phase>
         <goals>
           <goal>stop</goal>
         </goals>
       </execution>
     </executions>
</plugin>

Chúng ta đã có Selenium và Jetty server đây là các server test và web application đã được cấu hình tự động khởi động với integration test phase của Maven build lifecycle.

Tiếp theo chúng ta viết một đoạn html trong file src/main/webapp/ index.jsp

 <html>
     <body>
       <h1>Hello, World</h1>
     </body>
</html>

Khi jetty server hoạt động truy cập vô http://localhost:8080/mywebapp bạn sẽ thấy “Hello, World”.

Selenium test case của chúng ta sẽ load các thành phần của http://localhost:8080/mywebapp và kiểm tra có tồn tại “Hello World” hay không.

public class SeleniumHelloWorldExample extends TestCase{
    private DefaultSelenium selenium;

    @Override
    public void setUp() throws Exception {
        super.setUp();
        selenium = createSeleniumClient("http://localhost:8080/");
        selenium.start();
    }
    @Override
    public void tearDown() throws Exception {
        selenium.stop();
        super.tearDown();
    }
    protected DefaultSelenium createSeleniumClient(String url) throws
            Exception {
        return new DefaultSelenium("localhost", 4444, "*firefox", url);
    }
    @Test
    public void testHelloWorld() throws Exception {
        try {
            selenium.open("http://localhost:8080/mywebapp/index.jsp");
            assertEquals("Hello, World", selenium.getText("//h1"));
        } catch (SeleniumException ex) {
            fail(ex.getMessage());
            throw ex;
        }
    }
    
}

Để thực hiện itegration test bạn sử dụng comand line sau trong thư mục gốc của project.

$  mvn integration-test

Vừa rồi mình đã giới thiệu các kỹ thuật cơ bản sử dụng trong một Maven Project hy vọng với các kỹ thuật này sẽ giúp ích cho công việc của các bạn.

Tài liệu tham khảo: Apache maven 3 cookbook.


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.