
譯者 | 李睿
審校 | 重樓
在日常開發工作中,無論是后端工程師還是API開發人員,幾乎都會面臨一個共同的需求:如何獲取高質量的模擬數據。
無論是在測試新的API、為了演示填充數據庫,還是讓單元測試用例更加貼近真實場景,都需要借助模擬數據來完成。但問題在于,很多常見的模擬數據顯得過于“生硬”和“重復”——例如反復出現的“John Doe”和“123 Main Street”。這不僅降低了測試的真實性,也在向團隊或客戶演示時影響了整體體驗。
本文將探索DataFaker和EasyRandom這兩個功能強大的Java庫,它們可以輕而易舉地生成大量且逼真的模擬數據。
這并不只是簡單地生成姓名與郵箱,還將演示如何在Spring Boot 3項目中無縫集成它們,并結合二者優勢以發揮最大作用。最終,你將學會如何構建一個可直接返回模擬數據的 REST API。
這并不是紙上談兵,而是配備了真實可用的代碼示例,確保能夠在項目中直接應用。
為什么要生成模擬數據?
開發人員通常面對這樣的現實:人工制作測試數據既耗時又容易出錯。
假設開發人員正在開發一個用戶管理系統。需要測試分頁、過濾、排序和邊緣情況(例如缺失電子郵件或者非常長的姓名)。與其人工編寫100行示例JSON,不如立即自動并即時生成,這不是更好嗎?
優質的模擬數據可以幫助開發人員:
- 在更真實的場景中驗證其邏輯。
- 使用“看起來真實”的數據展示原型。
- 使用可變輸入對API或UI組件進行壓力測試。
- 自動化單元測試,無需樣板“模擬構建器”。
因此,開發人員不再輸入人工模擬數據,而是讓DataFaker和EasyRandom來完成繁重的工作。
DataFaker:現代化以及改進版的JavaFaker
對于曾經使用過JavaFaker的開發人員來說,DataFaker 是其現代化且得到積極維護的后繼產品。
它專為現代Java 生態(Java 17+)構建,不僅性能優異,更提供了涵蓋姓名、地址、財務信息、公司數據、互聯網數據以及加密密鑰等數百種數據類別,能夠滿足多樣化的測試數據需求。
以下是一個簡單的示例:
Java
import net.datafaker.Faker;
Faker faker = new Faker();
System.out.println(faker.name().fullName());
System.out.println(faker.internet().emailAddress());
System.out.println(faker.address().fullAddress());在運行之后,將會得到類似這樣的結果:
Plain Text
Matilde Marques
matilde.marques@techmail.com
Rua do Carmo 45, 1200-093 Lisboa此外,通過其區域設置功能,生成的數據還能根據不同的地區動態調整,實現內容的本地化。
Java
Faker faker = new Faker(new Locale("pt"));現在,生成的數據已經可以匹配開發人員所使用的語言和所在地區——這無疑為國際化測試帶來了極大便利。
EasyRandom:超越字段填充的智能對象生成器
與專注于生成逼真字段數據的DataFaker不同,EasyRandom(前身為Random Beans)提供了另一種思路。
當面對包含復雜結構(如實體類或DTO)的Java對象,并希望自動填充隨機但符合規范的數據時,EasyRandom顯得尤為實用。
可以將其視為一個智能的“對象構建引擎”:它不僅能填充基本類型字段,還能自動處理嵌套對象、集合(如List、Map)等復雜結構,輕松生成完整且結構正確的對象實例。
示例:
Java
import org.jeasy.random.EasyRandom;
EasyRandom easyRandom = new EasyRandom();
Person randomPerson = easyRandom.nextObject(Person.class);這將創建一個完全填充的Person實例,其中包含隨機字符串、數字,甚至嵌套屬性。
因此,DataFaker提供了真實感(例如,“John Smith, john@smith.com”),EasyRandom提供了對象結構的自動化構建能力(例如填充整個POJO圖)。
最佳實踐是將二者結合使用:讓EasyRandom創建對象,然后使用DataFake更加可信的數據來修飾特定的字段。
DataFaker與EasyRandom的結合:最佳選擇
這就是事情變得有趣的地方。
為此將創建一個小型Spring Boot REST API,它公開用于生成虛擬用戶的端點。每個用戶將有一個id、fullName、email、phone和address。你將使用DataFaker實現真實感,使用EasyRandom實現自動化。項目結構如下:
Plain Text
src/
├─ main/java/com/example/fakedata/
│ ├─ Application.java
│ ├─ config/
│ ├─ api/
│ ├─ controller/
│ ├─ domain/
│ ├─ dto/
│ ├─ service/
│ └─ mapper/
└─ resources/
└─ static/index.html用戶域分類
為了保持簡潔的原則,使用Lombok來避免樣板代碼:
Java
@Data
@Builder
public class User {
private String id;
private String fullName;
private String email;
private String phone;
private String address;
}對于API響應,將使用Java記錄(Java record)實現不可變性和可讀性:
Java
public record UserDto(String id, String fullName, String email, String phone, String address) { }服務:兩個庫相結合
這是項目的核心:
Java
@Service
public class DataGenService {
private final Faker faker = new Faker(Locale.ENGLISH);
private final EasyRandom easyRandom;
public DataGenService() {
EasyRandomParameters params = new EasyRandomParameters()
.seed(System.currentTimeMillis())
.stringLengthRange(5, 20);
this.easyRandom = new EasyRandom(params);
}
public User randomUserViaDatafaker() {
return User.builder()
.id(UUID.randomUUID().toString())
.fullName(faker.name().fullName())
.email(faker.internet().emailAddress())
.phone(faker.phoneNumber().cellPhone())
2 .address(faker.address().fullAddress())
.build();
}
public User randomUserViaEasyRandom() {
User u = easyRandom.nextObject(User.class);
if (u.getId() == null || u.getId().isBlank()) {
u.setId(UUID.randomUUID().toString());
}
u.setFullName(faker.name().fullName());
u.setEmail(faker.internet().emailAddress());
return u;
}
public List<User> manyUsers(int count, boolean easyRandomMode) {
return IntStream.range(0, count)
.mapToObj(i -> easyRandomMode ? randomUserViaEasyRandom() : randomUserViaDatafaker())
.collect(Collectors.toList());
}
}可以看到上例如何使用DataFaker實現真實感以及使用EasyRandom構建結構。二者的協作,就像默契配合的兩位廚師:一位專注構建菜肴的整體架構與食材搭配,另一位則精心調配風味與細節。最終,它們共同呈現出的是結構完整、細節逼真的高質量數據。
REST控制器
現在,通過REST API來使其具備可訪問性。
Java
@RestController
@RequestMapping("/api/users")
public class UserController {
private final DataGenService service;
public UserController(DataGenService service) {
this.service = service;
}
@GetMapping("/{count}")
public ApiResponse<List<UserDto>> generateUsers(@PathVariable int count,
@RequestParam(defaultValue = "false") boolean easy) {
List<UserDto> users = service.manyUsers(count, easy)
.stream().map(UserMapper::toDto)
.collect(Collectors.toList());
return ApiResponse.of(users);
}
}為了使API響應一致,將所有內容包裝在一個帶有時間戳的信封中:
Java
public record ApiResponse<T>(T data, Instant timestamp) {
public static <T> ApiResponse<T> of(T data) {
return new ApiResponse<>(data, Instant.now());
}
}這樣,每個API調用都會返回這樣的數據:
JSON
{
"data": [
{
"id": "e7b1c37a-8b20-43c1-8ff3-b4aef8d89c3a",
"fullName": "Lina Cordeiro",
"email": "lina.cordeiro@example.com",
"phone": "+351 912 345 678",
"address": "Rua do Comércio 12, Porto"
}
],
"timestamp": "2025-10-06T13:02:45.321Z"
}這樣處理更加清晰且易于調試。
為什么在響應中添加時間戳?
當在分布式系統中調試請求或當客戶端記錄響應時,在有效負載中直接包含服務器時間戳有助于關聯事件——這是一個具有宏觀效益的微觀細節。
為什么兩個庫結合使用更好?
有人會問,“為什么不單獨使用DataFaker?”這是一個很好的問題:
- DataFaker在生成逼真數據方面表現出色,但它不擅長自動填充深層次的對象結構。
- 另一方面,EasyRandom擅長處理復雜的對象圖,但其隨機性往往顯得“過于合成”——例如像“asdlkfj@example.com”這樣缺乏真實感的示例。
將兩者結合,能夠獲得以下優勢:
- 真實感和自動化的統一
- 與測試框架及API的無縫集成
- 通過配置與隨機種子確保數據的一致性
這有點像將隨機單詞生成器與翻譯器結合起來:一個提供了豐富多樣的詞匯,而另一個則將這些詞匯組織成結構完整、意義明確的篇章。
更進一步:Postman、Docker和CI/CD
完整的項目還包括:
- 用于快速測試的Postman集合
- 用于容器化的Dockerfile和docker-compose.yml
- 用于自動化構建和依賴項更新的GitHub Actions CI和Dependabot設置
這使得這個小演示成為一個用于測試和學習的生產級參考項目。
如果正在指導初級開發人員或構建內部工具,這是一個展示清晰架構和可重復數據生成的推薦示例。
代碼庫:github.com/wallaceespindola/fake-data-springboot
使用這一設置的實際想法
- 負載測試:生成數千個模擬用戶來填充數據庫。
- UI原型設計:用逼真的API數據為前端提供數據。
- 演示環境:采用動態樣本用戶填充沙盒環境。
- 單元測試:用對DataGenService.randomUserViaDatafaker()的調用替換new User("a","b")。
- 數據匿名化:快速采用模擬數據替換敏感的生產數據。
這些都是這種組合發揮重要作用的真實場景。
結束語
讓測試數據從令人乏味的模擬數據,轉變為引人入勝的“真實”演示,其秘訣就在于所選擇的工具。
使用DataFaker和EasyRandom,可以自動化實現該過程——使用現代Java、更少的代碼以及完美組合的庫。不僅可以在構建測試或模擬API時節省時間,還可以提供生動、多樣和逼真的演示。
這一切都構建于開源、輕量的基礎之上,并能輕松融入開發人員熟悉的任何技術堆棧——無論是Spring Boot、Quarkus、Micronaut,還是簡單的控制臺應用程序。
現在是告別模擬數據的時候了,為開發的項目提供個性與真實感的數據,可以讓Java完成這些繁重的工作。
需要了解更多的技術見解?可以查看GitHub代碼庫和LinkedIn頁面。
原文標題:Building Realistic Test Data in Java: A Hands-On Guide for Developers,作者:Wallace Espindola





























