Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

springjpa+junit5+mockito+querydsl #3329

Open
liuluyang06 opened this issue Apr 27, 2024 · 0 comments
Open

springjpa+junit5+mockito+querydsl #3329

liuluyang06 opened this issue Apr 27, 2024 · 0 comments

Comments

@liuluyang06
Copy link

Current version in use:

querydsl-version 5.00 + jdk1.8 +junit5

How is this problem caused?

jpa can chain to generate sql statement objects, but now trying to mock this method, there is a stub parameter mismatch, mainly:

doReturn(jpaQuery).when(jpaQuery).orderBy(any(OrderSpecifier.class));
I can't change it to this
doReturn(jpaQuery).when(jpaQuery).orderBy(any(OrderSpecifier[].class));

The reproduction steps:

1、JUnit test code:

`class AdminEventServiceImplTestOne {

@mock
private JpaBase jpaBase ;

@mock
EntityManager entityManager;

@mock
private JPAQueryFactory jpa ;

@mock
private JPAQuery jpaQuery;

@Injectmocks
private AdminEventServiceImpl yourService;

private List expectedEntities;

private ClusterEventListQo qo;
@beforeeach
public void setup() {
expectedEntities =Arrays.asList(new ClusterEventListVo(), new ClusterEventListVo());
qo = new ClusterEventListQo();
qo.setClusterId(0L);
qo.setServiceType(DeployServiceType.Graph);
PageQo pageQo = new PageQo();
pageQo.setPageNo(1);
pageQo.setPageSize(10);

when(jpa.select(any(Expression.class))).thenReturn(jpaQuery);
doReturn(jpaQuery).when(jpaQuery).from(any(EntityPath.class));
when(jpaQuery.where(any(Predicate.class))).thenReturn(jpaQuery);
doReturn(jpaQuery).when(jpaQuery).orderBy(any(OrderSpecifier.class));
when(jpaQuery.limit(anyLong())).thenReturn(jpaQuery);
when(jpaQuery.offset(anyLong())).thenReturn(jpaQuery);
when(jpaQuery.fetch()).thenReturn(expectedEntities);

}
@test
public void testFindClusterEventList2() {
PageResponse result= yourService.findClusterEventList(qo);
assertNotNull(result, "The result should not be null");
assertEquals(expectedEntities.size(), result.getPayload().getTotal(), "The size of the result list should be equal to the expected list");
}
`

2、The tested business service implementation class method::

`@slf4j
@service
public class AdminEventServiceImpl extends JpaBase implements AdminEventService {

private static ExecutorService executorService = new ThreadPoolExecutor(4, 8, 60L, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(2096), new ThreadPoolExecutor.CallerRunsPolicy());

@Autowired
private AdminClusterEventDao adminClusterEventDao;

@OverRide
public PageResponse findClusterEventList(ClusterEventListQo qo) {
QAdminClusterEventPo adminClusterEventTable = QAdminClusterEventPo.adminClusterEventPo;
BooleanBuilder builder = buildClusterEventListQueryCondition(qo, adminClusterEventTable);

PageQo pageQo = qo.getPage();
List<OrderSpecifier> orderSpecifiers = buildClusterEventSortCondition(pageQo, adminClusterEventTable);

JPAQuery<ClusterEventListVo> jpaQuery = jpa.select(Projections.bean(ClusterEventListVo.class,
                adminClusterEventTable.id.as("id"),
                adminClusterEventTable.eventType.as("eventType"),
                adminClusterEventTable.eventName.as("eventName"),
                adminClusterEventTable.serviceType.as("serviceType"),
                adminClusterEventTable.namespace.as("namespace"),
                adminClusterEventTable.hostName.as("hostName"),
                adminClusterEventTable.ip.as("ip"),
                adminClusterEventTable.resultType.as("resultType"),
                adminClusterEventTable.firstHappenTime.as("happenTime"),
                adminClusterEventTable.happenCount.as("happenCount"),
                adminClusterEventTable.operator.as("operator"),
                adminClusterEventTable.eventDetail.as("eventDetail")
        )).from(adminClusterEventTable)
        .where(builder);
List<ClusterEventListVo> clusterEventListVos = jpaQuery.orderBy(orderSpecifiers.toArray(new OrderSpecifier[]{}))
        .offset(pageQo.getPageSize() * (pageQo.getPageNo() - 1L))
        .limit(pageQo.getPageSize()).fetch();

if (CollectionUtils.isEmpty(clusterEventListVos)) {
    return PageResponse.success(Collections.emptyList(), 0L, pageQo);
}
long total = jpaQuery.fetchCount();
return PageResponse.success(clusterEventListVos, total, pageQo);

}`

3、The parent class from which the current service inherits: related to jpa
`@slf4j
@NoRepositoryBean
public class JpaBase {

@Autowired
@PersistenceContext
private EntityManager entityManager;

protected JPAQueryFactory jpa;

@value("${batch.size:1000}")
private int batchSize;

@resource
private DataSourceProperties dataSourceProperties;

@PostConstruct
public void initFactory() {
jpa = new JPAQueryFactory(entityManager);
}

protected void setUpdateBy(T bean, String userId) {
if (Objects.isNull(bean.getId()) || StringUtils.isBlank(bean.getCreatedBy())) {
bean.setCreatedBy(userId);
}
bean.setUpdatedBy(userId);
}

public Expression buildExpression(Object path) {
if (!(path instanceof Path) || !(path instanceof DslExpression)) {
return null;
}
return ((DslExpression) path).as(((Path) path).getMetadata().getName());
}

public Expression buildExpression(Object path, String alias) {
if (!(path instanceof Path) || !(path instanceof DslExpression)) {
return null;
}
return ((DslExpression) path).as(alias);
}

/**

  • get entity's table name
  • @param poCls
  • @param
  • @return
    */
    public String getPoTableName(Class poCls) {
    Table annotation = poCls.getAnnotation(Table.class);
    return annotation.name();
    }

/**

  • get entity's sequence name
  • @param poCls
  • @param
  • @return
    */
    public String getSequenceName(Class poCls) {
    Field[] fields = poCls.getDeclaredFields();
    for (Field field : fields) {
    GeneratedValue generatedValue = field.getAnnotation(GeneratedValue.class);
    if (generatedValue != null) {
    return generatedValue.generator();
    }
    }
    return null;
    }`

4、idea Error message:
`org.mockito.exceptions.misusing.PotentialStubbingProblem:
Strict stubbing argument mismatch. Please check:

this invocation of 'orderBy' method:
jpaQuery.orderBy(
adminClusterEventPo.id DESC
);
-> at com.haizhi.admin.server.restapi.service.impl.AdminEventServiceImpl.findClusterEventList(AdminEventServiceImpl.java:89)

has following stubbing(s) with different arguments:

jpaQuery.orderBy(null);
-> at com.haizhi.admin.server.restapi.service.impl.AdminEventServiceImplTestOne.setup(AdminEventServiceImplTestOne.java:73)
Typically, stubbing argument mismatch indicates user mistake when writing tests.
Mockito fails early so that you can debug potential problem easily.
However, there are legit scenarios when this exception generates false negative signal:
stubbing the same method multiple times using 'given().will()' or 'when().then()' API
Please use 'will().given()' or 'doReturn().when()' API for stubbing.

stubbed method is intentionally invoked with different arguments by code under test
Please use default or 'silent' JUnit Rule (equivalent of Strictness.LENIENT).
For more information see javadoc for PotentialStubbingProblem class.

at com.haizhi.admin.server.restapi.service.impl.AdminEventServiceImpl.findClusterEventList(AdminEventServiceImpl.java:89)
at com.haizhi.admin.server.restapi.service.impl.AdminEventServiceImplTestOne.testFindClusterEventList2(AdminEventServiceImplTestOne.java:80)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
`
last:

Or how to write a unit test for the findClusterEventList method of the business class AdminEventServiceImpl above. Thanks for answering!!

I traced it back by looking at the source code:
org.mockito.internal.invocation.MatcherApplicationStrategy#forEachMatcherAndArgument
isAssignableFrom method is still not solved. The main problem is that it cannot match an object of type OrderSpecifier. This is an inner class of querydsl, which is annotated with @immutable and has no child class or parent class.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant