成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

如何為復雜的 Java 應用編寫集成測試,你學會了嗎?

開發 前端
不知道大家注意到剛才測試代碼存在的問題沒有,主要就是沒法斷言。因為客戶端、route、server 都是以一個應用的維度去運行的,沒法獲取到一些關鍵指標。比如輸出在線用戶,當客戶端作為一個應用時,在線用戶就是直接打印在了終端,而沒有直接暴露一個接口返回在線數據;收發消息也是同理。
這段時間比較重大的更新就是把元數據中心抽離出來了,以前是和 zookeeper 的代碼強耦合在一起的,重構之后可以有多種實現了。

今后甚至可以提供一個 jar 包就可以把后端服務全部啟動起來用于體驗,此時就可以使用一個簡單的基于內存的注冊中心。

除此之外做的更多的就是新增了一個集成測試的模塊,沒有完善的集成測試功能在合并代碼的時候都要小心翼翼,基本的功能需求都沒法保證。

加上這幾年我也接觸了不少優秀的開源項目(比如 Pulsar、OpenTelemetry、HertzBeat 等),他們都有完整的代碼合并流程;首先第一點就得把測試流水線跑通過。

這一點在 OpenTelemetry 社區更為嚴格:

圖片圖片

他們的構建測試流程非常多,包括單元測試、集成測試、代碼風格、多版本兼容等。

所以在結合了這些優秀項目的經驗后我也為 cim 項目新增相關的模塊 cim-integration-test,同時也在 github 上配置了相關的 action,最終的效果如下:

圖片圖片

圖片圖片

在 “Build with Maven” 階段觸發單元測試和集成測試,最終會把測試結果上傳到 Codecov,然后會在 PR 的評論區輸出測試報告。

圖片圖片

相關的 action 配置如下:

圖片圖片

就是配置了幾個 Job,重點是這里的:

mvn -B package --file pom.xml

它會編譯并運行項目下面的所有 test 代碼。

cim-integration-test 模塊

為了方便進行集成測試,我新增了 cim-integration-test 這個模塊,這里面沒有任何源碼,只有測試相關的代碼。

圖片圖片

類的繼承關系圖如下:

圖片圖片

因為我們做集成測試需要把 cim 所依賴的服務都啟動起來,目前主要由以下幾個服務:

  • cim-server: cim 的服務端
  • cim-route: 路由服務
  • cim-client: 客戶端

而 route 服務是依賴于 server 服務,所以 route 繼承了 server,client 則是需要 route 和 server 都啟動,所以它需要繼承 route。

集成 test container

先來看看 server 的測試實現:

public abstract class AbstractServerBaseTest {  
  
    private static final DockerImageName DEFAULT_IMAGE_NAME = DockerImageName  
            .parse("zookeeper")  
            .withTag("3.9.2");  
  
    private static final Duration DEFAULT_STARTUP_TIMEOUT = Duration.ofSeconds(60);  
  
    @Container  
    public final ZooKeeperContainer  
            zooKeeperContainer = new ZooKeeperContainer(DEFAULT_IMAGE_NAME, DEFAULT_STARTUP_TIMEOUT);  
  
    @Getter  
    private String zookeeperAddr;  
  
    public void startServer() {  
        zooKeeperContainer.start();  
        zookeeperAddr = String.format("%s:%d", zooKeeperContainer.getHost(), zooKeeperContainer.getMappedPort(ZooKeeperContainer.DEFAULT_CLIENT_PORT));  
        SpringApplication server = new SpringApplication(CIMServerApplication.class);  
        server.run("--app.zk.addr=" + zookeeperAddr);  
    }  
}

因為 server 是需要依賴 zookeeper 作為元數據中心,所以在啟動之前需要先把 zookeeper 啟動起來。

此時就需要使用 testcontainer 來做支持了,使用它可以在單測的過程中使用 docker 啟動任意一個服務,這樣在 CI 中做集成測試就很簡單了。

圖片

我們日常使用的大部分中間件都是支持的,使用起來也很簡單。

先添加相關的依賴:

<dependencies>
    <dependency>
        <groupId>org.postgresql</groupId>
        <artifactId>postgresql</artifactId>
        <version>42.7.3</version>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.5.6</version>
    </dependency>
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter</artifactId>
        <version>5.10.2</version>
        <scope>test</scope>
    </dependency>
</dependencies>

然后在選擇我們需要依賴的服務,比如是 PostgreSQL:

<dependency>
    <groupId>org.testcontainers</groupId>
    <artifactId>postgresql</artifactId>
    <version>1.19.8</version>
    <scope>test</scope>
</dependency>

然后在測試代碼中啟動相關的服務

class CustomerServiceTest {

  static PostgreSQLContainer<?> postgres = new PostgreSQLContainer<>(
    "postgres:16-alpine"
  );

  CustomerService customerService;

  @BeforeAll
  static void beforeAll() {
    postgres.start();
  }

  @AfterAll
  static void afterAll() {
    postgres.stop();
  }

  @BeforeEach
  void setUp() {
    DBConnectionProvider connectionProvider = new DBConnectionProvider(
      postgres.getJdbcUrl(),
      postgres.getUsername(),
      postgres.getPassword()
    );
    customerService = new CustomerService(connectionProvider);
  }

通常情況下我們都是需要獲取這些中間件的鏈接,比如 IP 端口啥的。

org.testcontainers.containers.ContainerState#getHost
org.testcontainers.containers.ContainerState#getMappedPort

通常是通過這兩個函數來獲取對應的 IP 和端口。

集成

@Container  
RedisContainer redis = new RedisContainer(DockerImageName.parse("redis:7.4.0"));  
  
public void startRoute() {  
    redis.start();  
    SpringApplication route = new SpringApplication(RouteApplication.class);  
    String[] args = new String[]{  
            "--spring.data.redis.host=" + redis.getHost(),  
            "--spring.data.redis.port=" + redis.getMappedPort(6379),  
            "--app.zk.addr=" + super.getZookeeperAddr(),  
    };    
    route.setAdditionalProfiles("route");  
    route.run(args);  
}

對于 route 來說不但需要 zookeeper 還需要 Redis 來存放用戶的路由關系,此時就還需要運行一個 Redis 的容器,使用方法同理。

最后就需要以 springboot 的方式將這兩個應用啟動起來,我們直接創建一個 SpringApplication 對象,然后將需要修改的參數通過 --varname=value 的形式將數據傳遞進去。

還可以通過 setAdditionalProfiles() 函數指定當前應用運行的 profile,這樣我們就可以在測試目錄使用對應的配置文件了。

圖片圖片

route.setAdditionalProfiles("route");

比如我們這里設置為 route 就可以使用 application-route.yaml 作為 route 的配置文件啟動,就不用每個參數都通過 -- 傳遞了。

private void login(String userName, int port) throws Exception {  
    Long userId = super.registerAccount(userName);  
    SpringApplication client = new SpringApplication(CIMClientApplication.class);  
    client.setAdditionalProfiles("client");  
    String[] args = new String[]{  
            "--server.port=" + port,  
            "--cim.user.id=" + userId,  
            "--cim.user.userName=" + userName  
    };  
    client.run(args);  
}  
  
@Test  
public void olu() throws Exception {  
    super.startServer();  
    super.startRoute();  
    this.login("crossoverJie", 8082);  
    this.login("cj", 8182);  
    MsgHandle msgHandle = SpringBeanFactory.getBean(MsgHandle.class);  
    msgHandle.innerCommand(":olu");  
    msgHandle.sendMsg("hello");  
}

我們真正要測試的其實是客戶端的功能,只要客戶端功能正常,說明 server 和 route 也是正常的。

比如這里的 olu(oline user) 的測試流程是:

  • 啟動 server 和 route
  • 登錄注冊兩個賬號
  • 查詢出所有用戶
  • 發送消息

最終的測試結果如下,符合預期。

圖片圖片

碰到的問題

應用分層

不知道大家注意到剛才測試代碼存在的問題沒有,主要就是沒法斷言。

因為客戶端、route、server 都是以一個應用的維度去運行的,沒法獲取到一些關鍵指標。

比如輸出在線用戶,當客戶端作為一個應用時,在線用戶就是直接打印在了終端,而沒有直接暴露一個接口返回在線數據;收發消息也是同理。

其實在應用內部這些都是有接口的,但是作為一個整體的 springboot 應用就沒有提供這些能力了。

本質上的問題就是這里應該有一個 client-sdk 的模塊,client 也是基于這個 sdk 實現的,這樣就可以更好的測試相關的功能了。

之后就準備把 sdk 單獨抽離一個模塊,這樣可以方便基于這個 sdk 實現不同的交互,甚至做一個 UI 界面都是可以的。

編譯失敗

還有一個問題就是我是直接將 client/route/server 的依賴集成到 integration-test 模塊中:

<dependency>  
  <groupId>com.crossoverjie.netty</groupId>  
  <artifactId>cim-server</artifactId>  
  <version>${project.version}</version>  
  <scope>compile</scope>  
</dependency>  
  
<dependency>  
  <groupId>com.crossoverjie.netty</groupId>  
  <artifactId>cim-forward-route</artifactId>  
  <version>${project.version}</version>  
  <scope>compile</scope>  
</dependency>  
  
<dependency>  
  <groupId>com.crossoverjie.netty</groupId>  
  <artifactId>cim-client</artifactId>  
  <version>${project.version}</version>  
  <scope>compile</scope>  
</dependency>

在 IDEA 里直接點擊測試按鈕是可以直接運行這里的測試用例的,但是想通過 mvn test 時就遇到了問題。

圖片圖片

會在編譯期間就是失敗了,我排查了很久最終發現是因為這三個模塊應用使用了springboot 的構建插件:

<plugin>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-maven-plugin</artifactId>
 <executions>
  <execution>
   <goals>
    <goal>repackage</goal>
   </goals>
  </execution>
 </executions>
</plugin>

這幾個模塊最終會被打包成一個 springboot 的 jar 包,從而導致 integration-test 在編譯時無法加載進來從而使用里面的類。

暫時沒有找到好的解決辦法,我就只有把這幾個插件先去掉,需要打包時再手動指定插件。

mvn clean package spring-boot:repackage -DskipTests=true

其實這里的本質問題也是沒有分層的結果,最好還是依賴 route 和 server 的 SDK 進行測試。

現在因為有了測試的 CI 也歡迎大家來做貢獻,可以看看這里的 help want,有一些簡單易上手可以先搞起來。

圖片圖片

https://github.com/crossoverJie/cim/issues/135

參考鏈接:

  • https://github.com/crossoverJie/cim/pull/140
  • https://github.com/crossoverJie/cim/pull/144
責任編輯:武曉燕 來源: crossoverJie
相關推薦

2023-07-26 13:11:21

ChatGPT平臺工具

2024-07-10 08:26:02

開源項目測試

2023-04-26 00:41:36

A/B測試郵件數量

2024-01-19 08:25:38

死鎖Java通信

2024-10-07 09:12:33

2024-05-10 08:00:48

K8soperatorGitHub

2024-08-09 08:17:07

SSH服務器架構

2024-08-07 08:40:46

2022-07-11 09:00:37

依賴配置文件Mybati

2022-11-30 09:54:57

網絡令牌身份驗證

2024-02-02 11:03:11

React數據Ref

2023-08-01 12:51:18

WebGPT機器學習模型

2024-01-02 12:05:26

Java并發編程

2023-12-07 07:03:09

2023-04-14 09:04:07

測試TDBF單元測試

2023-01-26 00:28:45

前端測試技術

2023-01-28 10:40:56

Java虛擬機代碼

2023-03-17 16:44:44

Channel進程模型

2024-11-29 08:53:46

2022-07-08 09:27:48

CSSIFC模型
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩一区二区免费视频 | 亚洲成人精品国产 | 欧美精品第一页 | 精品在线观看入口 | 久久久久久久国产精品影院 | 国产真实乱对白精彩久久小说 | 日韩在线国产 | 天天躁日日躁狠狠躁2018小说 | 国产中文| 国产精品美女久久久久久不卡 | 青春草91| 免费黄色片在线观看 | 91国在线高清视频 | 嫩草视频网| 中文字幕av网站 | 亚洲精品免费在线 | 久久久精 | 在线免费观看亚洲 | 欧洲一区在线观看 | 国产96在线 | 99资源| 精品乱人伦一区二区三区 | 天天精品在线 | 国产成人精品一区二区三区四区 | 久久久久国产一区二区三区四区 | 久久精品青青大伊人av | 久草视频网站 | 国产精品a免费一区久久电影 | 久久精品欧美一区二区三区不卡 | 免费av一区二区三区 | 涩涩鲁亚洲精品一区二区 | 亚洲精品免费在线观看 | 羞羞视频网站免费观看 | 嫩草一区二区三区 | 免费观看成人av | 日韩欧美在线观看 | 久久久久久综合 | 欧美日韩电影一区二区 | 国产精品国产精品国产专区不片 | 伊人操| 日韩欧美在线不卡 |