test(namespace): add displayName/email assertions and new test coverage

- Controller: add displayName and email assertions to addMember and updateMemberRole tests
- QueryAppService: add listMembers tests for batch user enrichment and null degradation
- CommandAppService: add addMember/updateMemberRole tests for displayName/email population and graceful degradation

Addresses PR #236 review feedback comments:
- Issue 2: Controller tests now assert displayName and email from mocked UserAccount
- Issue 3: Service layer tests now cover batch query and null user degradation
This commit is contained in:
Rsweater 2026-04-07 18:48:53 +08:00
parent 03ac86f19d
commit 79140f310d
3 changed files with 152 additions and 2 deletions

View file

@ -211,7 +211,9 @@ class NamespacePortalControllerTest {
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(0))
.andExpect(jsonPath("$.data.userId").value("user-2"))
.andExpect(jsonPath("$.data.role").value("ADMIN"));
.andExpect(jsonPath("$.data.role").value("ADMIN"))
.andExpect(jsonPath("$.data.displayName").value("Alice"))
.andExpect(jsonPath("$.data.email").value("alice@example.com"));
}
@Test
@ -250,7 +252,9 @@ class NamespacePortalControllerTest {
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(0))
.andExpect(jsonPath("$.data.userId").value("user-2"))
.andExpect(jsonPath("$.data.role").value("OWNER"));
.andExpect(jsonPath("$.data.role").value("OWNER"))
.andExpect(jsonPath("$.data.displayName").value("Alice"))
.andExpect(jsonPath("$.data.email").value("alice@example.com"));
}
@Test

View file

@ -9,18 +9,24 @@ import static org.mockito.Mockito.when;
import com.iflytek.skillhub.auth.rbac.PlatformPrincipal;
import com.iflytek.skillhub.domain.namespace.Namespace;
import com.iflytek.skillhub.domain.namespace.NamespaceGovernanceService;
import com.iflytek.skillhub.domain.namespace.NamespaceMember;
import com.iflytek.skillhub.domain.namespace.NamespaceMemberService;
import com.iflytek.skillhub.domain.namespace.NamespaceRepository;
import com.iflytek.skillhub.domain.namespace.NamespaceRole;
import com.iflytek.skillhub.domain.namespace.NamespaceService;
import com.iflytek.skillhub.domain.namespace.NamespaceStatus;
import com.iflytek.skillhub.domain.namespace.NamespaceType;
import com.iflytek.skillhub.domain.user.UserAccount;
import com.iflytek.skillhub.domain.user.UserAccountRepository;
import com.iflytek.skillhub.dto.MemberResponse;
import com.iflytek.skillhub.dto.NamespaceLifecycleRequest;
import com.iflytek.skillhub.dto.NamespaceRequest;
import com.iflytek.skillhub.dto.UpdateMemberRoleRequest;
import com.iflytek.skillhub.exception.ForbiddenException;
import org.junit.jupiter.api.Test;
import org.springframework.test.util.ReflectionTestUtils;
import java.util.Optional;
import java.util.Set;
class NamespacePortalCommandAppServiceTest {
@ -74,4 +80,92 @@ class NamespacePortalCommandAppServiceTest {
namespace.setType(NamespaceType.TEAM);
return namespace;
}
@Test
void addMember_populatesDisplayNameAndEmail() {
Namespace ns = namespace(1L, "team-a");
NamespaceMember member = new NamespaceMember(1L, "user-2", NamespaceRole.ADMIN);
ReflectionTestUtils.setField(member, "id", 10L);
UserAccount user = new UserAccount("user-2", "Alice", "alice@example.com", null);
when(namespaceService.getNamespaceBySlug("team-a")).thenReturn(ns);
when(namespaceMemberService.addMember(1L, "user-2", NamespaceRole.ADMIN, "owner-1"))
.thenReturn(member);
when(userAccountRepository.findById("user-2"))
.thenReturn(Optional.of(user));
MemberResponse result = service.addMember("team-a", "user-2", NamespaceRole.ADMIN, "owner-1");
assertThat(result.userId()).isEqualTo("user-2");
assertThat(result.displayName()).isEqualTo("Alice");
assertThat(result.email()).isEqualTo("alice@example.com");
assertThat(result.role()).isEqualTo(NamespaceRole.ADMIN);
}
@Test
void addMember_withoutUserAccount_degradesGracefully() {
Namespace ns = namespace(1L, "team-a");
NamespaceMember member = new NamespaceMember(1L, "ghost", NamespaceRole.MEMBER);
ReflectionTestUtils.setField(member, "id", 20L);
when(namespaceService.getNamespaceBySlug("team-a")).thenReturn(ns);
when(namespaceMemberService.addMember(1L, "ghost", NamespaceRole.MEMBER, "owner-1"))
.thenReturn(member);
when(userAccountRepository.findById("ghost"))
.thenReturn(Optional.empty());
MemberResponse result = service.addMember("team-a", "ghost", NamespaceRole.MEMBER, "owner-1");
assertThat(result.userId()).isEqualTo("ghost");
assertThat(result.displayName()).isNull();
assertThat(result.email()).isNull();
}
@Test
void updateMemberRole_populatesDisplayNameAndEmail() {
Namespace ns = namespace(1L, "team-a");
NamespaceMember member = new NamespaceMember(1L, "user-2", NamespaceRole.OWNER);
ReflectionTestUtils.setField(member, "id", 10L);
UserAccount user = new UserAccount("user-2", "Alice", "alice@example.com", null);
when(namespaceService.getNamespaceBySlug("team-a")).thenReturn(ns);
when(namespaceMemberService.updateMemberRole(1L, "user-2", NamespaceRole.OWNER, "owner-1"))
.thenReturn(member);
when(userAccountRepository.findById("user-2"))
.thenReturn(Optional.of(user));
MemberResponse result = service.updateMemberRole(
"team-a", "user-2",
new UpdateMemberRoleRequest(NamespaceRole.OWNER),
"owner-1"
);
assertThat(result.userId()).isEqualTo("user-2");
assertThat(result.displayName()).isEqualTo("Alice");
assertThat(result.email()).isEqualTo("alice@example.com");
assertThat(result.role()).isEqualTo(NamespaceRole.OWNER);
}
@Test
void updateMemberRole_withoutUserAccount_degradesGracefully() {
Namespace ns = namespace(1L, "team-a");
NamespaceMember member = new NamespaceMember(1L, "ghost", NamespaceRole.MEMBER);
ReflectionTestUtils.setField(member, "id", 20L);
when(namespaceService.getNamespaceBySlug("team-a")).thenReturn(ns);
when(namespaceMemberService.updateMemberRole(1L, "ghost", NamespaceRole.ADMIN, "owner-1"))
.thenReturn(member);
when(userAccountRepository.findById("ghost"))
.thenReturn(Optional.empty());
MemberResponse result = service.updateMemberRole(
"team-a", "ghost",
new UpdateMemberRoleRequest(NamespaceRole.ADMIN),
"owner-1"
);
assertThat(result.userId()).isEqualTo("ghost");
assertThat(result.displayName()).isNull();
assertThat(result.email()).isNull();
}
}

View file

@ -1,20 +1,28 @@
package com.iflytek.skillhub.service;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyList;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import com.iflytek.skillhub.domain.namespace.Namespace;
import com.iflytek.skillhub.domain.namespace.NamespaceAccessPolicy;
import com.iflytek.skillhub.domain.namespace.NamespaceMember;
import com.iflytek.skillhub.domain.namespace.NamespaceMemberService;
import com.iflytek.skillhub.domain.namespace.NamespaceRepository;
import com.iflytek.skillhub.domain.namespace.NamespaceRole;
import com.iflytek.skillhub.domain.namespace.NamespaceService;
import com.iflytek.skillhub.domain.namespace.NamespaceStatus;
import com.iflytek.skillhub.domain.namespace.NamespaceType;
import com.iflytek.skillhub.domain.user.UserAccount;
import com.iflytek.skillhub.domain.user.UserAccountRepository;
import com.iflytek.skillhub.dto.MemberResponse;
import com.iflytek.skillhub.dto.PageResponse;
import org.junit.jupiter.api.Test;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.test.util.ReflectionTestUtils;
import java.util.List;
@ -70,4 +78,48 @@ class NamespacePortalQueryAppServiceTest {
namespace.setType(NamespaceType.TEAM);
return namespace;
}
@Test
void listMembers_withUserAccount_returnsDisplayNameAndEmail() {
Namespace ns = namespace(1L, "team-a");
NamespaceMember member = new NamespaceMember(1L, "user-2", NamespaceRole.ADMIN);
ReflectionTestUtils.setField(member, "id", 10L);
UserAccount user = new UserAccount("user-2", "Alice", "alice@example.com", null);
when(namespaceService.getNamespaceBySlug("team-a")).thenReturn(ns);
when(namespaceMemberService.listMembers(eq(1L), any(PageRequest.class)))
.thenReturn(new PageImpl<>(List.of(member), PageRequest.of(0, 20), 1));
when(userAccountRepository.findByIdIn(List.of("user-2")))
.thenReturn(List.of(user));
PageResponse<MemberResponse> result = service.listMembers("team-a", PageRequest.of(0, 20), "owner-1");
assertThat(result.items()).hasSize(1);
MemberResponse mr = result.items().get(0);
assertThat(mr.userId()).isEqualTo("user-2");
assertThat(mr.displayName()).isEqualTo("Alice");
assertThat(mr.email()).isEqualTo("alice@example.com");
assertThat(mr.role()).isEqualTo(NamespaceRole.ADMIN);
}
@Test
void listMembers_withoutUserAccount_returnsNullFields() {
Namespace ns = namespace(1L, "team-a");
NamespaceMember member = new NamespaceMember(1L, "ghost-user", NamespaceRole.MEMBER);
ReflectionTestUtils.setField(member, "id", 20L);
when(namespaceService.getNamespaceBySlug("team-a")).thenReturn(ns);
when(namespaceMemberService.listMembers(eq(1L), any(PageRequest.class)))
.thenReturn(new PageImpl<>(List.of(member), PageRequest.of(0, 20), 1));
when(userAccountRepository.findByIdIn(List.of("ghost-user")))
.thenReturn(List.of());
PageResponse<MemberResponse> result = service.listMembers("team-a", PageRequest.of(0, 20), "owner-1");
assertThat(result.items()).hasSize(1);
MemberResponse mr = result.items().get(0);
assertThat(mr.userId()).isEqualTo("ghost-user");
assertThat(mr.displayName()).isNull();
assertThat(mr.email()).isNull();
}
}