Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,29 @@ public interface WxCpTpUserService {
* @param departId 必填。部门id
* @param fetchChild 非必填。1/0:是否递归获取子部门下面的成员
* @param status 非必填。0获取全部员工,1获取已关注成员列表,2获取禁用成员列表,4获取未关注成员列表。status可叠加
* @param corpId 企业id
* @return the list
* @throws WxErrorException the wx error exception
*/
List<WxCpUser> listSimpleByDepartment(Long departId, Boolean fetchChild, Integer status, String corpId)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里在公共接口 WxCpTpUserService 上新增了一个非 default 方法签名,会对下游自定义实现该接口的项目造成编译期不兼容(必须新增实现)。建议确认这类 API 变更在当前版本发布语义下是可接受的。

Severity: medium

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.

throws WxErrorException;

/**
* <pre>
* 获取部门成员.
*
* http://qydev.weixin.qq.com/wiki/index.php?title=管理成员#.E8.8E.B7.E5.8F.96.E9.83.A8.E9.97.A8.E6.88.90.E5.91.98
* </pre>
*
* @param departId 必填。部门id
* @param fetchChild 非必填。1/0:是否递归获取子部门下面的成员
* @param status 非必填。0获取全部员工,1获取已关注成员列表,2获取禁用成员列表,4获取未关注成员列表。status可叠加
* @return the list
* @throws WxErrorException the wx error exception
* @deprecated 第三方应用调用此接口需要使用 corpId 对应的 access_token,请使用
* {@link #listSimpleByDepartment(Long, Boolean, Integer, String)}
*/
@Deprecated
List<WxCpUser> listSimpleByDepartment(Long departId, Boolean fetchChild, Integer status) throws WxErrorException;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,42 @@ public List<WxCpUser> listByDepartment(Long departId, Boolean fetchChild, Intege
}

@Override
public List<WxCpUser> listSimpleByDepartment(Long departId, Boolean fetchChild, Integer status, String corpId)
throws WxErrorException {
StringBuilder params = new StringBuilder();
if (fetchChild != null) {
params.append("fetch_child=").append(fetchChild ? "1" : "0");
}
if (status != null) {
if (params.length() > 0) {
params.append('&');
}
params.append("status=").append(status);
} else {
if (params.length() > 0) {
params.append('&');
}
params.append("status=0");
}
if (params.length() > 0) {
params.append('&');
}
params.append("access_token=")
.append(mainService.getWxCpTpConfigStorage().getAccessToken(corpId));

String url = mainService.getWxCpTpConfigStorage().getApiUrl(USER_SIMPLE_LIST + departId);
String responseContent = this.mainService.get(url, params.toString(), true);
JsonObject tmpJsonElement = GsonParser.parse(responseContent);
return WxCpGsonBuilder.create()
.fromJson(
tmpJsonElement.getAsJsonObject().get("userlist"),
new TypeToken<List<WxCpUser>>() {
}.getType()
);
}

@Override
@Deprecated
public List<WxCpUser> listSimpleByDepartment(Long departId, Boolean fetchChild, Integer status)
throws WxErrorException {
String params = "";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
package me.chanjar.weixin.cp.tp.service.impl;

import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.cp.bean.WxCpUser;
import me.chanjar.weixin.cp.config.WxCpTpConfigStorage;
import me.chanjar.weixin.cp.config.impl.WxCpTpDefaultConfigImpl;
import me.chanjar.weixin.cp.tp.service.WxCpTpUserService;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;
import org.testng.annotations.Test;

import java.util.List;

import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.User.USER_SIMPLE_LIST;
import static org.mockito.ArgumentMatchers.contains;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.testng.Assert.assertNotNull;

/**
* 企业微信-第三方开发-用户管理相关测试.
*
* @author GitHub Copilot
*/
public class WxCpTpUserServiceImplTest {

@Mock
private WxCpTpServiceApacheHttpClientImpl wxCpTpService;

@Mock
private WxCpTpConfigStorage configStorage;

private WxCpTpUserService wxCpTpUserService;

private AutoCloseable mockitoAnnotations;

/**
* Sets up.
*/
@BeforeClass
public void setUp() {
mockitoAnnotations = MockitoAnnotations.openMocks(this);
when(wxCpTpService.getWxCpTpConfigStorage()).thenReturn(configStorage);
WxCpTpDefaultConfigImpl defaultConfig = new WxCpTpDefaultConfigImpl();
when(configStorage.getApiUrl(contains(USER_SIMPLE_LIST)))
.thenAnswer(invocation -> defaultConfig.getApiUrl(invocation.getArgument(0)));
wxCpTpUserService = new WxCpTpUserServiceImpl(wxCpTpService);
}

/**
* Tear down.
*
* @throws Exception the exception
*/
@AfterClass
public void tearDown() throws Exception {
mockitoAnnotations.close();
}

/**
* 测试使用 corpId 的 listSimpleByDepartment 方法,验证请求使用了 access_token 而非 suite_access_token.
*
* @throws WxErrorException the wx error exception
*/
@Test
public void testListSimpleByDepartmentWithCorpId() throws WxErrorException {
Long departId = 1L;
String corpId = "test_corp_id";
String accessToken = "test_access_token";
String result = "{\"errcode\":0,\"errmsg\":\"ok\",\"userlist\":[{\"userid\":\"zhangsan\",\"name\":\"张三\"}]}";

when(configStorage.getAccessToken(corpId)).thenReturn(accessToken);
String url = new WxCpTpDefaultConfigImpl().getApiUrl(USER_SIMPLE_LIST + departId);
when(wxCpTpService.get(eq(url), contains("access_token=" + accessToken), eq(true))).thenReturn(result);

List<WxCpUser> users = wxCpTpUserService.listSimpleByDepartment(departId, true, 0, corpId);
assertNotNull(users);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

当前用例只断言了 users 非空,但如果解析逻辑回归成返回空列表,这个断言仍然会通过。建议再校验一下返回列表的元素数量/关键字段,以确保测试能真正覆盖到反序列化结果。

Severity: low

Fix This in Augment

🤖 Was this useful? React with 👍 or 👎, or 🚀 if it prevented an incident/outage.


// 验证调用时传入了 withoutSuiteAccessToken=true,确保不会附加 suite_access_token
verify(wxCpTpService).get(eq(url), contains("access_token=" + accessToken), eq(true));
}
}