You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

单元测试中如何设置JPA实体被AccessLevel.NONE修饰的属性?

如何设置被@Setter(AccessLevel.NONE)修饰的字段

当然有办法!针对你遇到的场景,这里有几种实用的解决方案:


方法1:使用Java反射(最直接,无需修改实体类)

Java反射可以绕过访问权限限制,直接给私有字段赋值。你可以在测试方法里添加这段代码:

@Test
public void testGetName() {
    int id = 2;
    User mockUser = new User();
    mockUser.setName("John");
    
    // 用反射设置id字段
    try {
        Field idField = User.class.getDeclaredField("id");
        idField.setAccessible(true); // 开启访问权限
        idField.set(mockUser, id);
    } catch (NoSuchFieldException | IllegalAccessException e) {
        e.printStackTrace();
        // 或者根据测试需要抛出RuntimeException
        throw new RuntimeException("Failed to set id via reflection", e);
    }
    
    Optional<User> mockUserOptional = Optional.of(mockUser);
    Mockito.when(userRepository.findById(id)).thenReturn(mockUserOptional);
    // 后续测试逻辑...
}

这种方法不需要修改你的实体类代码,非常适合临时测试场景。


方法2:给实体类添加测试友好的构造方法

如果你愿意微调实体类,可以添加一个包含id参数的构造方法,专门用于测试:

@NoArgsConstructor @Data @Entity
public class User {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Setter(AccessLevel.NONE)
    private int id;
    @Column(nullable = false)
    private String name;
    
    // 测试专用构造方法,包级访问权限即可(测试类和实体类同包的话)
    User(int id, String name) {
        this.id = id;
        this.name = name;
    }
}

然后在测试里直接用这个构造方法创建对象:

@Test
public void testGetName() {
    int id = 2;
    User mockUser = new User(id, "John"); // 直接用测试构造方法
    Optional<User> mockUserOptional = Optional.of(mockUser);
    Mockito.when(userRepository.findById(id)).thenReturn(mockUserOptional);
    // 后续测试逻辑...
}

这种方式更优雅,也避免了反射的复杂性。如果测试类和实体类不在同一个包,可以把构造方法的权限改成protected,或者用@VisibleForTesting注解(来自Google Guava或Spring Framework)标记,明确表示这个构造方法是为测试设计的。


方法3:使用Lombok的@Builder(可选)

如果你已经用了Lombok,可以给实体类添加@Builder注解,然后通过Builder来设置id字段:

@NoArgsConstructor @Data @Entity @Builder
public class User {
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Setter(AccessLevel.NONE)
    private int id;
    @Column(nullable = false)
    private String name;
    
    // 手动添加全参构造方法,适配@Builder(Lombok自动生成可能受@NoArgsConstructor影响)
    @Builder
    private User(int id, String name) {
        this.id = id;
        this.name = name;
    }
}

然后在测试里这样用:

@Test
public void testGetName() {
    int id = 2;
    User mockUser = User.builder().id(id).name("John").build();
    Optional<User> mockUserOptional = Optional.of(mockUser);
    Mockito.when(userRepository.findById(id)).thenReturn(mockUserOptional);
    // 后续测试逻辑...
}

这种方式适合本来就用Builder模式的项目,代码更简洁。


内容的提问来源于stack exchange,提问作者Phurinat Puekkham

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 07:36:29