天天看點

軟體測試學習筆記丨JUnit5并行資料同步

作者:測試人666
本文轉自測試人社群,原文連結:jck28-lucio-junit5并行資料同步 - 學習筆記 - 測試人社群

Synchronization

  • 共享資源的同步
  • JUnit5 以 @ResourceLock注解的形式為我們提供了這樣的機制。

串行用例

  • 可以看到單線程的時候每次測試用例斷言都通過,說明可以正确的拿到對應的值。

并行用例

  • 如果換成多線程的時候,可以看到代碼不穩定性,有時斷言通過,有時斷言失敗。
  • 這個時候如果想要進行對應的代碼健壯性應該怎樣修改呢??

@ResourceLock

  • @ResourceLock相當于Java代碼中的 synchronized 、@Synchronized
  • @ResourceLock注解為 測試類 和 測試方法 提供聲明式同步機制。
  • @ResourceLock注解有兩個參數
    • 一個是String指定唯一辨別共享資源的值
    • 資源值可以是 預定義 的或 使用者定義 的
      • 一個是ResourceAccessMode指定通路資源的模式
  • 通路模式可以是 READ 「隻讀」和 READ_WRITE「讀和寫」

多線程報錯

package com.junit5.synch;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.parallel.*;

import java.util.Properties;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;

@Execution(ExecutionMode.CONCURRENT)
public class ParallelResourceLockTest {

    Properties properties;

    @BeforeEach
    void before(){
        properties= new Properties(System.getProperties());
    }

    @Test
    void test01(){
        assertNull(System.getProperty("custom.property"));
    }

    @Test
    void test02(){
        System.setProperty("custom.property","juni5");
        assertEquals("juni5",System.getProperty("custom.property"));
    }

    @Test
    void test03(){
        System.setProperty("custom.property","hogwarts");
        assertEquals("hogwarts",System.getProperty("custom.property"));
    }
}           

加鎖

package com.junit5.synch;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.parallel.*;

import java.util.Properties;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;

@Execution(ExecutionMode.CONCURRENT)
public class ParallelResourceLockTest {

    Properties properties;

    @BeforeEach
    void before(){
        properties= new Properties(System.getProperties());
    }

    @Test
    @ResourceLock(value = Resources.SYSTEM_PROPERTIES,mode = ResourceAccessMode.READ)
    void test01(){
        assertNull(System.getProperty("custom.property"));
    }

    @Test
    @ResourceLock(value = Resources.SYSTEM_PROPERTIES,mode = ResourceAccessMode.READ_WRITE)
    void test02(){
        System.setProperty("custom.property","juni5");
        assertEquals("juni5",System.getProperty("custom.property"));
    }

    @Test
    @ResourceLock(value = Resources.SYSTEM_PROPERTIES,mode = ResourceAccessMode.READ_WRITE)
    void test03(){
        System.setProperty("custom.property","hogwarts");
        assertEquals("hogwarts",System.getProperty("custom.property"));
    }
}           

預定義資源

  • Resources.SYSTEM_PROPERTIES
    • 表示 Java 的系統屬性。
  • Resources.SYSTEM_OUT
    • 代表目前程序的标準輸出流。
  • Resources.SYSTEM_ERR
    • 表示目前程序的标準錯誤流。
  • Resources.LOCALE
    • 目前 JVM 執行個體的預設語言環境。
  • Resources.TIMEZONE
    • 目前 JVM 執行個體的預設時區。

自定義資源

  • 全局使用者
  • 如果是SAME_THREAD,運作測試用例的斷言結果都是正常,但是當使用了并發執行,對應的用例就會報錯。
  • 解決:
    • 在對應測試方法上添加相關的 @ResourceLock

自定義資源

  • 1.自定義類的全限定類名為value值
  • 2.如果是沒有值的寫入,對應 mode 為READ「隻可讀」;
    • 如果有内容寫入自定義類,對應mode 為 READ_WRITE「既可讀又可寫」
package com.junit5;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

public class User {
    static Map<Integer,String> global_user = new HashMap<>();

    public static String get(int id){
        return global_user.get(id);
    }

    public static void add(int id,String user){
        global_user.put(id,user);
    }

    public static void update(int id,String user){
        global_user.put(id,user);
    }

    public static void remove(int id){
        global_user.remove(id);
    }

    public static void clear(){
        global_user.clear();
    }

    public static Collection<String> getUser(){
        return global_user.values();
    }
}
package com.junit5.synch;

import com.junit5.User;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.parallel.*;

import java.util.Properties;

import static org.junit.jupiter.api.Assertions.*;

@Execution(ExecutionMode.CONCURRENT)
public class ParallelResourceLock02Test {

    public static final String GOLOBAL_USER = "com.junit5.User.user";

    @BeforeEach
    void before(){
        User.clear();
    }

    @Test
    @ResourceLock(value = GOLOBAL_USER,mode = ResourceAccessMode.READ)
    void test01(){
        System.out.println("test01==>"+User.getUser());
       assertTrue(User.getUser().isEmpty());
    }

    @Test
    @ResourceLock(value = GOLOBAL_USER,mode = ResourceAccessMode.READ_WRITE)
    void test02(){
      User.add(1,"gaoyuanyuan");
        System.out.println("test02==>"+User.getUser());
        assertEquals("gaoyuanyuan",User.get(1));
    }

    @Test
    @ResourceLock(value = GOLOBAL_USER,mode = ResourceAccessMode.READ_WRITE)
    void test03(){
        User.update(1,"liushishi");
        System.out.println("test03==>"+User.getUser());
        assertEquals("liushishi",User.get(1));
    }

    @Test
    @ResourceLock(value = GOLOBAL_USER,mode = ResourceAccessMode.READ_WRITE)
    void test04(){
        User.add(2,"guanzhiling");
        System.out.println("test04==>"+User.getUser());
        User.remove(2);
        System.out.println("test02==>remove==>"+User.getUser());
        assertNull(User.get(2));
    }

}           

總結

并行測試對應共享資料可以通過 @ResourceLock 來進行資料的同步

軟體測試開發免費視訊教程分享 - 公衆号 - 測試人社群

軟體測試學習筆記丨JUnit5并行資料同步

繼續閱讀