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

JUnit测试Querydsl查询方法时断言错误问题求助

嘿,我来帮你搞定这个断言错误的问题!从你给出的错误信息和代码来看,问题出在你对业务方法返回的Tuple结构理解错了,导致断言的时候拿错了对象。

问题根源分析

你的业务方法btnSearchClick里用了Projections.bean(Account.class, ...)把查询结果投影成一个Account对象,然后把这个对象放到了Tuple里。所以返回的List<Tuple>中,每个Tuple的第一个元素就是这个投影生成的Account实例。而你在测试里直接写account.get(0),拿到的是整个Account对象,不是你期望的sLocation字段值,这就导致了expected:<ON> but was:<com.spacestudy.model.Account@783f5f71>的错误。

另外还有两个隐藏的坑你得注意:

  • 业务方法里的查询条件是account.nInstId.eq(60),但你测试保存Account的时候没设置nInstId=60,这会导致查询结果为空,执行account.get(0)的时候直接抛IndexOutOfBoundsException。
  • 测试用例里的sAcctDesc、sInvestigatorName、sClientDeptId这些变量没初始化,传空值的话可能影响查询结果(另外看你业务方法参数是这四个,但查询逻辑里没加对应的过滤条件,后续如果要实现过滤记得补充)。

修复方案

1. 修正测试用例的断言逻辑

你需要从Tuple里取出投影的Account对象,再获取它的sLocation属性来断言:

@Test 
public void btnSearchClick() throws Exception { 
    // 初始化测试参数
    String sAcctDesc = "SRIRAM";
    String sInvestigatorName = "Ram, Sri";
    String sClientDeptId = "120010";

    // 先保存关联实体,避免外键约束问题
    Department dep = new Department(); 
    dep.setsDeptName("Deans Office"); 
    dep.setsClientDeptId("120010");
    departmentRepo.save(dep);

    Investigator invest = new Investigator(); 
    invest.setsInvestigatorName("Ram, Sri");
    investigatorRepo.save(invest);

    AccountCPCMapping cpc = new AccountCPCMapping(); 
    cpc.setsCCPCode("RT");
    accountCPCMappingRepo.save(cpc);

    // 保存测试Account,必须设置nInstId匹配查询条件
    Account acc = new Account(); 
    acc.setsLocation("ON"); 
    acc.setsAcctDesc("SRIRAM"); 
    acc.setsClientAcctId("1124100"); 
    acc.setInvestigator(invest); 
    acc.setDepartment(dep); 
    acc.setAccountCPC(cpc);
    acc.setnInstId(60); // 关键:匹配业务方法的where条件
    accountRepo.save(acc); 

    // 调用业务方法
    List<Tuple> result = accountService.btnSearchClick("1124100", sAcctDesc, sInvestigatorName, sClientDeptId); 

    // 从Tuple中取出Account对象,再获取sLocation断言
    Account returnedAccount = result.get(0).get(0, Account.class);
    assertEquals(acc.getsLocation(), returnedAccount.getsLocation()); 
}

2. 优化业务方法(可选但推荐)

既然你已经用Projections.bean投影成了Account对象,其实没必要返回List<Tuple>,直接返回List<Account>会更清晰,也能避免后续的Tuple操作错误。修改业务方法:

public List<Account> btnSearchClick(String sClientAcctId, String sAcctDesc, String sInvestigatorName, String sClientDeptId) throws Exception { 
    QAccount account = QAccount.account; 
    QDepartment department = QDepartment.department; 
    QAccountCPCMapping accountCPCMapping = QAccountCPCMapping.accountCPCMapping; 
    QInvestigator investigator = QInvestigator.investigator; 

    JPAQuery<Account> query = new JPAQuery<>(em); 
    query.select(Projections.bean(Account.class, 
            account.sClientAcctId, 
            account.sAcctDesc, 
            account.sLocation, 
            Projections.bean(Department.class, department.sDeptName, department.sClientDeptId).as("department"), 
            Projections.bean(Investigator.class, investigator.sInvestigatorName).as("investigator"), 
            Projections.bean(AccountCPCMapping.class, accountCPCMapping.sCCPCode).as("accountCPC")))
        .from(account) 
        .innerJoin(account.department, department)
        .innerJoin(account.accountCPC, accountCPCMapping)
        .innerJoin(account.investigator, investigator)
        .where(account.nInstId.eq(60)); 

    // 补充:如果要实现参数过滤,记得添加对应条件
    // if (StringUtils.isNotEmpty(sClientAcctId)) {
    //     query.where(account.sClientAcctId.eq(sClientAcctId));
    // }
    // ...其他参数的过滤逻辑

    return query.fetch(); 
}

修改后测试用例可以直接断言返回的Account对象属性:

List<Account> result = accountService.btnSearchClick("1124100", sAcctDesc, sInvestigatorName, sClientDeptId); 
assertEquals(acc.getsLocation(), result.get(0).getsLocation());

总结

核心问题就是你误把Tuple里的Account对象当成了sLocation字段,调整断言逻辑就能解决。同时别忘了设置匹配查询条件的nInstId,以及先保存关联的实体,这样测试才能正常运行。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 06:44:05