Fastjson&thrift


Fastjson&thrift

Alibaba Fastjson

一、Fastjson 简介与运用场景
Fastjson 是阿里巴巴开源的高性能 JSON 处理库,主要用于 Java 对象与 JSON 数据之间的序列化和反序列化。它具有速度快、功能完备、使用简单等特点,在 Java 开发领域被广泛应用‌

‌主要运用场景包括‌:

‌前后端数据交互‌:在 Web 开发中,将 Java 对象序列化为 JSON 返回给前端,或接收前端 JSON 数据反序列化为 Java 对象‌
‌微服务通信‌:服务间通过 HTTP 接口传递 JSON 格式数据时的高效处理‌
‌数据库存储‌:将复杂对象结构以 JSON 形式存储到数据库字段中‌
‌消息队列处理‌:如 Kafka 消息的 JSON 格式解析与封装‌
‌配置文件解析‌:读取和解析 JSON 格式的配置文件‌
二、安装步骤
Fastjson 的安装主要通过 Maven 依赖管理实现,以下是详细步骤:

‌Maven 项目引入‌:
在项目的 pom.xml 文件中添加以下依赖(推荐使用最新稳定版本):

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>2.0.49</version>
</dependency>

‌非 Maven 项目‌:
可以直接下载 fastjson 的 jar 包,添加到项目的 classpath 中‌

‌版本选择建议‌:

新项目建议直接使用 fastjson2(包名 com.alibaba.fastjson2)
旧项目升级时注意包名变更(v1 是 com.alibaba.fastjson)‌
三、核心使用方法

  1. 基本序列化与反序列化
    ‌Java 对象转 JSON 字符串‌:
User user = new User("张三", 25);
String jsonString = JSON.toJSONString(user);
// 输出: {"age":25,"name":"张三"}

‌JSON 字符串转 Java 对象‌:

String jsonStr = "{\"name\":\"李四\",\"age\":30}";
User user = JSON.parseObject(jsonStr, User.class);
  1. 集合处理
    ‌List 序列化‌:
List<User> userList = new ArrayList<>();
userList.add(new User("王五", 28));
userList.add(new User("赵六", 32));
String listJson = JSON.toJSONString(userList);

‌JSON 数组反序列化‌:

String arrayJson = "[{\"name\":\"张三\"},{\"name\":\"李四\"}]";
List<User> users = JSON.parseArray(arrayJson, User.class);
  1. 复杂对象处理
    ‌处理嵌套对象‌:
class Order {
    private String orderId;
    private User user;
    // getters & setters
}

Order order = new Order();
order.setOrderId("123456");
order.setUser(new User("张三", 25));

String orderJson = JSON.toJSONString(order);
// 输出: {"orderId":"123456","user":{"age":25,"name":"张三"}}
  1. 格式化输出
    String prettyJson = JSON.toJSONString(obj, SerializerFeature.PrettyFormat);

四、高级特性与实战示例

  1. 自定义序列化
    ‌解决 Long 类型精度丢失问题‌:
public class User {
    @JSONField(serializeUsing = ToStringSerializer.class)
    private Long id;
    // 其他字段...
}
  1. 日期格式处理
public class Event {
 @JSONField(format = "yyyy-MM-dd HH:mm:ss")
 private Date createTime;
 // 其他字段..
}
  1. 字段别名
public class Product {
 @JSONField(name = "product_name")
 private String name;
 // 其他字段...
}

五、性能优化建议
‌重用 JSON 实例‌:避免频繁创建 JSON 解析实例‌
‌使用最新版本‌:Fastjson 持续优化性能并修复安全问题‌
‌合理选择序列化特性‌:根据需求选择适当的 SerializerFeature‌
‌大文件处理‌:对于超大 JSON 文件,使用流式 API 处理‌
六、安全注意事项
‌及时升级版本‌:Fastjson 历史上存在一些安全漏洞,建议保持最新版本‌
‌反序列化安全‌:不要反序列化不可信的 JSON 数据‌
‌生产环境验证‌:升级版本前应在测试环境充分验证‌

JSONObject常用函数

一、基础创建与初始化

  1. 构造函数

    • JSONObject():创建空JSON对象‌
    • JSONObject(String jsonString):从JSON字符串创建对象‌
    • JSONObject(Map map):从Map创建对象‌
  2. put()方法

    • 添加键值对,若key存在则覆盖原值‌
    CodeJSONObject obj = new JSONObject();
    obj.put("name", "John");
    obj.put("age", 30);
    
  3. append()方法

    • 将值添加到数组,若key不存在则创建新数组‌
    javaCopy Codeobj.append("hobbies", "reading");
    obj.append("hobbies", "swimming");
    

二、数据获取方法

  1. getXxx()系列

    • getString(key):获取字符串值‌
    • getInt(key):获取整数值‌
    • getBoolean(key):获取布尔值‌
    • getInteger(key)
  2. ‌**getJSONObject()**‌

    • 获取嵌套JSON对象‌
    Object address = obj.getJSONObject("address");
    String city = address.getString("city");
    
  3. ‌**getJSONArray()**‌

    • 获取JSON数组‌4
    JSONArray hobbies = obj.getJSONArray("hobbies");
    

三、实用工具方法

  1. ‌**has()**‌

    • 检查键是否存在‌1
    boolean hasName = obj.has("name");
    
  2. optXxx()系列

    • 安全获取值,键不存在时返回默认值‌
    String name = obj.optString("name", "Unknown");
    
  3. ‌**keySet()**‌

    • 获取所有键的集合‌6
    Set<String> keys = obj.keySet();
    
  4. ‌**toString()**‌

    • 将JSONObject转为JSON字符串‌
    String jsonString = obj.toString();
    

四、高级操作

  1. ‌**toMap()**‌

    • 将JSONObject转为Map‌
    Map<String, Object> map = obj.toMap();
    
  2. ‌**accumulate()**‌

    • 类似append(),但会合并相同key的值到数组‌2
    Codeobj.accumulate("skills", "Java");
    obj.accumulate("skills", "Python");
    

JSON字符串转JSONObject

  1. 使用org.json库

    CodeString jsonStr = "{\"name\":\"John\", \"age\":30}";
    JSONObject jsonObject = new JSONObject(jsonStr);
    

    这是最基础直接的转换方式,通过JSONObject构造函数实现‌

  2. 使用Fastjson库

    JSONObject obj = JSONObject.parseObject(jsonStr);
    

    Fastjson提供了更高效的解析方式,适合处理复杂JSON结构‌

  3. 使用Gson库

    JsonObject jsonObject = JsonParser.parseString(jsonStr).getAsJsonObject();
    

    Gson由Google开发,支持更灵活的配置选项‌

JSONObject转字符串

  1. toString()方法

    String jsonString = jsonObject.toString();
    

    这是最常用的转换方式,适用于所有JSON库‌

  2. ‌**Fastjson的toJSONString()**‌

    String str = JSON.toJSONString(jsonObject);
    

    Fastjson提供了更高效的序列化方法‌9

  3. ‌**Gson的toJson()**‌

    String json = new Gson().toJson(jsonObject);
    

    Gson支持自定义日期格式等高级特性‌

对象与JSON互转

  1. Java对象转JSON字符串

    Person person = new Person("John", 30);
    String json = JSONObject.fromObject(person).toString();
    

    这种方式需要引入net.sf.json库‌

  2. JSON对象转Java对象

    Person person = JSONObject.toBean(jsonObject, Person.class);
    

    需要目标类有无参构造函数‌

  3. 使用Fastjson的parseObject

    Person person = JSON.parseObject(jsonStr, Person.class);
    

    Fastjson支持更复杂的对象转换‌

集合与JSON互转

  1. List转JSON数组

    List<Person> list = new ArrayList<>();
    String jsonArray = JSONArray.fromObject(list).toString();
    

    适用于处理对象集合‌

  2. JSON数组转List

    List<Person> persons = JSON.parseArray(jsonArray, Person.class);
    

    Fastjson提供了便捷的数组处理方法‌

  3. Map转JSON

    Map<String, Object> map = new HashMap<>();
    String json = JSONObject.fromObject(map).toString();
    

    适合处理键值对数据结构‌

注意事项

  1. 依赖管理
    不同JSON库需要添加对应的依赖,
    • 简单场景:org.json
    • 高性能需求:Fastjson
    • 复杂配置:Gson‌79
  2. 特殊字符处理
    JSON字符串中的引号等特殊字符需要转义,否则会导致解析失败

TestNG

一、TestNG 简介与主要运用场景
TestNG 是 Java 生态中功能强大的测试框架,其名称中的 “NG” 代表 “Next Generation”,表明它是新一代测试框架。TestNG 不仅支持单元测试,还能胜任复杂的集成测试和端到端测试‌

‌主要运用场景包括‌:

‌接口自动化测试‌:结合 HttpClient 等工具实现接口测试自动化‌
‌Web 自动化测试‌:与 Selenium 集成进行功能测试‌
‌单元测试‌:虽然开发人员更常用 JUnit,但 TestNG 同样适用‌
‌集成测试‌:处理模块间交互和系统级测试‌
‌参数化测试‌:支持数据驱动测试模式‌
‌并行测试‌:提高测试执行效率‌
二、安装与配置步骤

  1. Maven 项目安装
    在 pom.xml 中添加依赖(推荐使用最新稳定版本):
<dependency>
    <groupId>org.testng</groupId>
    <artifactId>testng</artifactId>
    <version>7.9.0</version>
    <scope>test</scope>
</dependency>
  1. IDE 插件安装
    ‌IntelliJ IDEA‌:

通过 Preferences > Plugins 搜索安装 TestNG 插件
安装成功后重启 IDEA,会显示”Create testng XML”选项‌
‌Eclipse‌:

在 Help > Eclipse Marketplace 中搜索 TestNG
或通过更新站点 http://beust.com/eclipse 安装‌
三、核心注解详解
TestNG 通过注解控制测试流程,以下是常用注解及其执行顺序:

  1. 套件级别注解
    @BeforeSuite:整个测试套件开始前执行一次‌
    @AfterSuite:整个测试套件结束后执行一次‌

  2. 测试类级别注解
    @BeforeClass:测试类实例化后执行‌
    @AfterClass:测试类所有方法执行完毕后执行‌

  3. 测试方法级别注解
    @BeforeMethod:每个测试方法执行前运行‌
    @AfterMethod:每个测试方法执行后运行‌
    @Test:标记测试方法的核心注解‌

  4. 特殊功能注解
    @Parameters:参数化测试‌
    @DataProvider:提供测试数据‌
    @Test(dependsOnMethods = “…”):定义测试依赖‌
    @Test(timeOut = 1000):设置超时时间‌
    四、核心功能与使用方法

  5. 基础测试用例编写

import org.testng.Assert;
import org.testng.annotations.Test;

public class BasicTest {
    @Test
    public void testAddition() {
        int result = 2 + 2;
        Assert.assertEquals(result, 4, "加法计算错误");
    }
}
  1. 参数化测试
    ‌通过 @Parameters 实现‌:
@Test
@Parameters({"a", "b", "expected"})
public void testWithParameters(int a, int b, int expected) {
    Assert.assertEquals(a + b, expected);
}
//通过 @DataProvider 实现‌:

@DataProvider(name = "testData")
public Object[][] provideData() {
    return new Object[][] {
        {1, 1, 2},
        {2, 3, 5}
    };
}

@Test(dataProvider = "testData")
public void testDataProvider(int a, int b, int expected) {
    Assert.assertEquals(a + b, expected);
}
  1. 依赖测试
@Test
public void login() {
    System.out.println("登录操作");
   }

@Test(dependsOnMethods = "login")
public void accessDashboard() {
    System.out.println("访问仪表盘");
}

//4. 分组测试
@Test(groups = "smoke")
public void smokeTest1() {
    // 冒烟测试用例
}

@Test(groups = "regression")
public void regressionTest1() {
    // 回归测试用例
}

五、测试套件配置与执行

  1. testng.xml 配置示例

    <!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
    <suite name="TestSuite">
     <test name="RegressionTests">
         <groups>
             <run>
                 <include name="regression"/>
             </run>
         </groups>
         <classes>
             <class name="com.example.RegressionTest"/>
         </classes>
     </test>
    </suite>
    
  2. 执行方式
    ‌IDE 中直接运行‌:右键测试类或方法选择”Run”
    ‌通过 testng.xml 运行‌:右键 xml 文件选择”Run”
    ‌命令行执行‌:java -cp “path/to/testng.jar” org.testng.TestNG testng.xml
    ‌Maven 执行‌:mvn test‌
    六、高级特性与最佳实践

  3. 并行测试
    在 testng.xml 中配置:

<suite name="ParallelSuite" parallel="methods" thread-count="5">

支持 parallel 属性值:methods/tests/classes/instances‌4

  1. 监听器实现
    自定义监听器监控测试事件:
public class CustomListener implements ITestListener {
    @Override
    public void onTestStart(ITestResult result) {
        System.out.println("Test started: " + result.getName());
    }
    // 实现其他接口方法...
}
  1. 测试报告
    TestNG 默认生成 HTML 报告,位置在 test-output 文件夹。也可集成 ExtentReports 等第三方报告库增强报告功能‌

七、实际应用示例

  1. Selenium 集成测试

public class LoginTest {
    WebDriver driver;
   
    @BeforeMethod
    public void setup() {
        driver = new ChromeDriver();
        driver.get("https://example.com/login");
    }
   
    @Test
    public void testValidLogin() {
        driver.findElement(By.id("username")).sendKeys("admin");
        driver.findElement(By.id("password")).sendKeys("password");
        driver.findElement(By.id("login-btn")).click();
        Assert.assertTrue(driver.getCurrentUrl().contains("dashboard"));
    }
   
    @AfterMethod
    public void tearDown() {
        driver.quit();
    }
}
  1. REST API 测试
public class ApiTest {
 @Test
 public void testGetUser() {
     RestAssured.baseURI = "https://api.example.com";
     Response response = given()
         .header("Authorization", "Bearer token")
         .when()
         .get("/users/1");
     Assert.assertEquals(response.getStatusCode(), 200);
      Assert.assertEquals(response.jsonPath().getString("name"), "John Doe");
      }
}

Thrift接口自动化测试

一、Thrift接口自动化测试工具与库
Thrift接口自动化测试通常需要以下核心工具和库:

‌Thrift编译器‌
用于将.thrift接口定义文件生成目标语言的客户端和服务端代码,支持多语言如Java、Python等‌

‌编程语言相关库‌

Python: thrift库(通过pip安装)、unittest/pytest测试框架‌
Java: libthrift依赖(Maven配置)、JUnit测试框架‌
通用: requests库(HTTP接口测试)‌
‌持续集成工具‌
Jenkins可用于构建自动化测试流水线,配合Ant实现测试任务调度‌

‌辅助工具‌
虚拟环境工具:virtualenv(Python环境隔离)‌
测试报告工具:HTMLTestRunner(生成可视化报告)‌
python+requests 接口自动化测试实战

jmeter+ant+jenkins接口自动化测试框架

Thrift安装与配置步骤

基础环境安装
‌安装依赖工具‌

# Ubuntu/Debian
sudo apt-get install automake bison flex g++ git libboost-all-dev libevent-dev libssl-dev libtool make pkg-config

‌下载并安装Thrift‌

wget https://archive.apache.org/dist/thrift/0.17.0/thrift-0.17.0.tar.gz
tar -zxvf thrift-0.17.0.tar.gz
cd thrift-0.17.0
./configure && make
sudo make install

‌验证安装‌
thrift -version

成功安装会显示版本号‌

语言特定环境配置
‌Python环境‌:

pip install thrift requests pytest

‌Java环境‌:
在pom.xml中添加:

<dependency>
  <groupId>org.apache.thrift</groupId>
  <artifactId>libthrift</artifactId>
  <version>0.17.0</version>
</dependency>

三、接口用例编写规范与示例

  1. Thrift IDL接口定义示例
    首先需要定义.thrift文件描述接口:
    example.thrift
namespace py example
struct User {
  1: i32 id,
  2: string name,
  3: string email
}

service UserService {
  User getUser(1: i32 userId),
  bool addUser(1: User user),
  list getAllUsers()
}
  1. Python测试用例示例
    使用pytest框架编写测试用例:
import pytest
from thrift import Thrift
from thrift.transport import TSocket
from thrift.transport import TTransport
from thrift.protocol import TBinaryProtocol

from example import UserService
from example.ttypes import User

class TestUserService:
    @pytest.fixture(scope="class")
    def client(self):
        # 初始化Thrift客户端连接
        transport = TSocket.TSocket('localhost', 9090)
        transport = TTransport.TBufferedTransport(transport)
        protocol = TBinaryProtocol.TBinaryProtocol(transport)
        client = UserService.Client(protocol)
        transport.open()
        yield client
        transport.close()

    def test_get_user(self, client):
        # 测试获取用户接口
        user = client.getUser(1)
        assert user.id == 1
        assert isinstance(user.name, str)

    def test_add_user(self, client):
        # 测试添加用户接口
        new_user = User(id=100, name="test", email="test@example.com")
        result = client.addUser(new_user)
        assert result is True
  1. Java测试用例示例
    使用JUnit框架编写测试用例:
import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.protocol.TProtocol;
import org.apache.thrift.transport.TSocket;
import org.apache.thrift.transport.TTransport;
import org.junit.Test;
import static org.junit.Assert.*;

public class TestUserService {
    
    @Test
    public void testGetUser() {
        try {
            TTransport transport = new TSocket("localhost", 9090);
            transport.open();
            TProtocol protocol = new TBinaryProtocol(transport);
            UserService.Client client = new UserService.Client(protocol);
            
            User user = client.getUser(1);
            assertEquals(1, user.getId());
            assertNotNull(user.getName());
            
            transport.close();
        } catch (TException e) {
            fail("Test failed with exception: " + e.getMessage());
        }
    }
}

四、常用注解与测试函数

  1. Python(pytest)常用注解
    @pytest.fixture: 定义测试夹具,如初始化客户端连接‌
    @pytest.mark.parametrize: 参数化测试用例‌
    @pytest.mark.skip: 跳过特定测试用例
    @pytest.mark.timeout: 设置测试超时时间
  2. 常用断言函数
    assertEqual(a, b): 验证a等于b
    assertTrue(x): 验证x为True
    assertRaises(exception): 验证代码抛出指定异常
    assertIsNone(x): 验证x为None
    assertIn(a, b): 验证a在b中
  3. 测试组织方式
    ‌按接口分类‌
    每个接口一个测试类,类中每个测试用例方法测试一个场景‌

‌测试数据管理‌
使用JSON/YAML文件管理测试数据,通过fixture加载‌

‌测试套件组织‌
使用TestSuite或pytest的discover功能自动发现并运行所有测试‌

使用Java+TestNG+Thrift实现的完整接口定义和自动化测试示例

‌标准项目结构‌

src/
  main/
    java/          # Java源代码
    thrift/        # Thrift接口定义文件
  test/
    java/          # 测试代码
target/
  generated-sources/ # Thrift生成的代码
pom.xml            # Maven配置文件

关键文件位置‌

Thrift接口文件:src/main/thrift/user.thrift
测试类文件:src/test/java/com/example/UserServiceTest.java
生成的Thrift代码:target/generated-sources/thrift/
user.thrift

namespace java com.example.thrift

struct User {
  1: i32 id,
  2: string username,
  3: string email
}

service UserService {
  User getUser(1: i32 userId),
  bool createUser(1: User user),
  list listUsers()
}

Thrift接口定义文件,包含User结构体和三个服务方法
‌生成Java代码

thrift --gen java -out src/main/java src/main/thrift/user.thrift

Pom.xml

<dependencies>
  <!-- Thrift依赖 -->
  <dependency>
    <groupId>org.apache.thrift</groupId>
    <artifactId>libthrift</artifactId>
    <version>0.17.0</version>
  </dependency>
  
  <!-- TestNG -->
  <dependency>
    <groupId>org.testng</groupId>
    <artifactId>testng</artifactId>
    <version>7.7.0</version>
    <scope>test</scope>
  </dependency>
</dependencies>

Maven项目配置文件,包含Thrift和TestNG依赖。
UserServiceTest.java

import org.apache.thrift.TException;
import org.apache.thrift.protocol.TBinaryProtocol;
import org.apache.thrift.transport.TSocket;
import org.testng.annotations.*;
import static org.testng.Assert.*;

import com.example.thrift.User;
import com.example.thrift.UserService;

public class UserServiceTest {
    private UserService.Client client;
    private TSocket transport;

    @BeforeClass
    public void setup() throws TException {
        transport = new TSocket("localhost", 9090);
        transport.open();
        client = new UserService.Client(
            new TBinaryProtocol(transport)
        );
    }

    @Test(priority = 1, description = "测试创建用户")
    public void testCreateUser() throws TException {
        User newUser = new User()
            .setId(1)
            .setUsername("testuser")
            .setEmail("test@example.com");
        
        boolean result = client.createUser(newUser);
        assertTrue(result, "用户创建失败");
    }

    @Test(priority = 2, dependsOnMethods = "testCreateUser",
          dataProvider = "userIds")
    public void testGetUser(int userId) throws TException {
        User user = client.getUser(userId);
        assertNotNull(user, "获取用户失败");
        assertEquals(user.getId(), userId, "用户ID不匹配");
    }

    @Test(priority = 3)
    public void testListUsers() throws TException {
        java.util.List<User> users = client.listUsers();
        assertFalse(users.isEmpty(), "用户列表不应为空");
        assertTrue(users.size() >= 1, "至少应有一个用户");
    }

    @DataProvider(name = "userIds")
    public Object[][] userIdProvider() {
        return new Object[][]{{1}, {2}};
    }

    @AfterClass
    public void tearDown() {
        if (transport != null) {
            transport.close();
        }
    }
}

关键组件解析
‌TestNG注解‌
@BeforeClass/@AfterClass: 测试类级别初始化和清理
@Test: 标记测试方法,可设置优先级(priority)和依赖(dependsOnMethods)
@DataProvider: 为测试方法提供参数化数据‌35

Thrift客户端组件‌
TSocket: Thrift传输层实现,建立TCP连接
TBinaryProtocol: 二进制协议编码解码
UserService.Client: Thrift生成的客户端桩‌

断言方法‌
assertTrue/assertFalse: 验证布尔条件
assertEquals: 验证相等性
assertNotNull: 验证非空
assertFalse(users.isEmpty()): 验证集合非空‌

运行与执行
‌通过Maven运行测试‌

mvn test

测试报告‌
TestNG会生成HTML格式的测试报告,位于target/surefire-reports目录下,包含测试通过率、执行时间等详细信息‌

持续集成‌
可以集成到Jenkins等CI工具中,实现自动化测试流水线‌

最佳实践建议
‌测试隔离‌
每个测试方法应该是独立的,不依赖其他测试方法的状态‌

‌异常测试‌
添加测试用例验证接口的异常处理能力:

@Test(expectedExceptions = TException.class)
public void testGetNonExistUser() throws TException {
    client.getUser(999); // 不存在的用户ID
}

性能考虑‌
对于高频调用接口,可以添加性能测试注解:

@Test(invocationCount = 10, threadPoolSize = 3)
public void testConcurrentAccess() throws TException {
    // 并发测试代码
}

测试数据管理‌
使用外部文件(如JSON)管理测试数据,提高可维护性‌

‌Mock测试‌
对于依赖外部服务的测试,可以使用Mock框架模拟Thrift服务端响应‌

通过以上步骤,您可以构建一个完整的Java+TestNG+Thrift接口自动化测试解决方案,确保接口的质量和稳定性

使用Java+TestNG+Thrift+Mockito实现的完整示例

src/main/thrift/user_service.thrift

namespace java com.example.thrift

enum UserType {
  NORMAL,
  VIP,
  ADMIN
}

struct User {
  1: i32 id,
  2: string username,
  3: UserType type,
  4: map attributes
}

exception UserNotFoundException {
  1: string message
}

service UserService {
  User getUser(1: i32 userId) throws (1: UserNotFoundException e),
  bool createUser(1: User user),
  list listUsersByType(1: UserType type)
}

Thrift接口定义了包含枚举、复杂结构和异常处理的用户服务
Pom.xml

<dependencies>
  <dependency>
    <groupId>org.apache.thrift</groupId>
    <artifactId>libthrift</artifactId>
    <version>0.17.0</version>
  </dependency>
  <dependency>
    <groupId>org.testng</groupId>
    <artifactId>testng</artifactId>
    <version>7.7.0</version>
    <scope>test</scope>
  </dependency>
  <dependency>
    <groupId>org.mockito</groupId>
    <artifactId>mockito-core</artifactId>
    <version>4.8.0</version>
    <scope>test</scope>
  </dependency>
</dependencies>

项目依赖配置包含Thrift、TestNG和Mockito

import org.apache.thrift.TException;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.testng.annotations.*;
import static org.testng.Assert.*;
import static org.mockito.Mockito.*;

import com.example.thrift.*;
import java.util.*;

public class UserServiceMockTest {
    @Mock
    private UserService.Client mockClient;
    
    private AutoCloseable closeable;

    @BeforeClass
    public void initMocks() {
        closeable = MockitoAnnotations.openMocks(this);
    }

    // 模拟正常用户数据
    @Test
    public void testGetNormalUser() throws TException {
        User mockUser = new User()
            .setId(1)
            .setUsername("normal_user")
            .setType(UserType.NORMAL)
            .setAttributes(new HashMap<>());
        
        when(mockClient.getUser(1)).thenReturn(mockUser);
        
        User result = mockClient.getUser(1);
        assertEquals(result.getType(), UserType.NORMAL);
        assertTrue(result.getUsername().contains("user"));
    }

    // 模拟异常情况
    @Test(expectedExceptions = UserNotFoundException.class)
    public void testGetNonExistUser() throws TException {
        when(mockClient.getUser(999))
            .thenThrow(new UserNotFoundException("User not found"));
        
        mockClient.getUser(999);
    }

    // 模拟集合类型数据
    @Test
    public void testListVipUsers() throws TException {
        List<User> mockUsers = Arrays.asList(
            new User().setId(1).setType(UserType.VIP),
            new User().setId(2).setType(UserType.VIP)
        );
        
        when(mockClient.listUsersByType(UserType.VIP))
            .thenReturn(mockUsers);
        
        List<User> result = mockClient.listUsersByType(UserType.VIP);
        assertEquals(result.size(), 2);
        assertTrue(result.stream().allMatch(u -> u.getType() == UserType.VIP));
    }

    // 模拟复杂结构数据
    @Test
    public void testUserWithAttributes() throws TException {
        Map<String, String> attrs = new HashMap<>();
        attrs.put("department", "R&D");
        attrs.put("level", "3");
        
        User mockUser = new User()
            .setId(3)
            .setAttributes(attrs);
        
        when(mockClient.getUser(3)).thenReturn(mockUser);
        
        User result = mockClient.getUser(3);
        assertEquals(result.getAttributes().get("department"), "R&D");
    }

    @AfterClass
    public void releaseMocks() throws Exception {
        closeable.close();
    }
}

使用@Mock注解创建Thrift客户端Mock对象
模拟了四种典型场景:正常数据、异常抛出、集合返回和复杂结构
包含基础类型、枚举、Map和List等多种数据类型的模拟
通过Mockito的when().thenReturn()和when().thenThrow()设置模拟行为
测试验证包含基本断言和集合操作断言
执行流程:

先编译thrift定义生成Java代码
运行mvn test执行测试
测试会使用Mock对象而非真实服务端
扩展建议:

可以结合@DataProvider实现参数化Mock测试
对于复杂业务逻辑,可以验证方法调用次数(verify)
可以使用@MockBean集成Spring环境测试

六、最佳实践建议
‌接口测试覆盖率‌
应覆盖所有接口方法,包括正常和异常场景‌

‌测试数据清理‌
每个测试用例执行后应清理测试数据,避免相互影响‌

‌性能考虑‌
对于高频调用接口,添加性能测试用例验证响应时间‌

‌持续集成‌
将自动化测试集成到CI/CD流程中,如Jenkins‌8

‌测试报告‌
使用HTMLTestRunner等工具生成可视化测试报告‌

Java项目运行报错OutOfMemoryError: insufficient memory

‌调整编译器堆内存‌
进入IDEA设置 → Build, Execution, Deployment → Compiler → 修改Compiler process heap size (Mbytes)为 ‌700-1024MB‌(8GB内存设备建议值)

此配置仅影响编译过程,不改变运行时内存。

‌清理IDE缓存‌
执行 File → Invalidate Caches → 勾选清除选项并重启IDEA7


文章作者: 读序
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 读序 !
  目录