如何Mock CriteriaQuery.where()及后续orderBy?代码测试遇阻求助
Hey there! Let's tackle this CriteriaQuery mocking issue you're having—those chained method calls can be tricky, but we'll get it sorted out.
The Core Issue: Chained Method Mock Consistency
The biggest pitfall with mocking CriteriaQuery.where().orderBy() is that every chained method call needs to return the same mock instance (since JPA's Criteria API uses fluent/chained returns, where each method returns this). If your mock returns null or a different instance after where(), calling orderBy() will throw a NPE or fail to register the mock.
Step-by-Step Fixes
1. Ensure Your CriteriaQuery Mock Returns Itself for Chained Calls
First, create your mock CriteriaQuery and explicitly configure it to return itself whenever where() or orderBy() is called:
// Mock the CriteriaQuery instance CriteriaQuery<YourEntity> criteriaQuery = mock(CriteriaQuery.class); // Critical: Make where() return the same mock instance when(criteriaQuery.where(any(Predicate.class))).thenReturn(criteriaQuery); // Then configure orderBy() to also return the same mock when(criteriaQuery.orderBy(any(Order.class))).thenReturn(criteriaQuery);
This ensures the chain where().orderBy() stays connected to your mock, instead of breaking with a null or unrelated object.
2. Mock Dependencies Like Predicate and Order
If your code uses CriteriaBuilder to create Predicate or Order objects (which it almost certainly does), you need to mock those too to avoid null references:
// Mock CriteriaBuilder and its returned objects CriteriaBuilder criteriaBuilder = mock(CriteriaBuilder.class); Predicate mockPredicate = mock(Predicate.class); Order mockOrder = mock(Order.class); // Configure CriteriaBuilder to return your mocked Predicate/Order when(criteriaBuilder.equal(any(Expression.class), any(Object.class))) .thenReturn(mockPredicate); when(criteriaBuilder.asc(any(Expression.class))) .thenReturn(mockOrder);
Now when your production code calls cb.equal(...) or cb.asc(...), it gets valid mock objects to pass to where() and orderBy().
3. Verify Call Order (If Needed)
If your test needs to confirm that where() is called before orderBy(), use Mockito's InOrder to validate the sequence:
InOrder inOrder = inOrder(criteriaQuery); inOrder.verify(criteriaQuery).where(any(Predicate.class)); inOrder.verify(criteriaQuery).orderBy(any(Order.class));
This catches cases where the method order might be flipped accidentally.
4. Avoid Over-Mocking Traps
Don't mock methods you don't care about—Mockito will return default values (like null for objects) for unconfigured methods, but if those methods are part of the chain, you'll break things. Stick to mocking only the methods your code actually uses.
Quick Troubleshooting Check
If you're still failing tests, double-check:
- Did you forget to make
where()return the mockCriteriaQuery? This is the #1 cause of chain failures. - Are your
Predicate/Ordermocks being passed correctly to the query methods? - Is your test injecting the mocked
CriteriaQueryinto the service/repository under test properly?
内容的提问来源于stack exchange,提问作者Sudeep Krishnan M

