fix(interaction): 收藏计数同步维护并新增评论数接口

This commit is contained in:
Zhou Weidong committed 2026-10-21 11:33:59 +08:00
1 parent 88794b816e
commit 65e8fbfc70
11 files changed
+382 -47

No files matched your search

@@ -63,6 +63,12 @@ public class AppCommentController {
return Result.ok(commentService.page(SecurityUtils.getUserIdOrNull(), query));
}
@Operation(summary = "短剧评论总数(可匿名访问)")
@GetMapping("/count")
public Result<Long> count(@RequestParam Long dramaId) {
return Result.ok(commentService.countByDrama(dramaId));
}
@Operation(summary = "删除自己的评论")
@DeleteMapping("/{id}")
public Result<Void> delete(@PathVariable Long id) {
@@ -0,0 +1,43 @@
// Author: fruit.com.cn
package com.fruitshorts.app.controller;
import com.fruitshorts.app.support.ControllerContractSupport;
import com.fruitshorts.interaction.service.CommentService;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.test.web.servlet.MockMvc;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
/** 评论总数接口契约。 */
class AppCommentControllerContractTest {
private CommentService commentService;
private MockMvc mockMvc;
@BeforeEach
void setUp() {
commentService = mock(CommentService.class);
mockMvc = ControllerContractSupport.mockMvcOf(
new AppCommentController(commentService));
}
@Test
void should_return_comment_count_as_string_when_requested() throws Exception {
given(commentService.countByDrama(7L)).willReturn(9L);
mockMvc.perform(get("/app/comments/count").param("dramaId", "7"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(0))
.andExpect(jsonPath("$.data").value("9"))
.andExpect(jsonPath("$.data").isString());
verify(commentService).countByDrama(7L);
}
}
@@ -0,0 +1,57 @@
// Author: fruit.com.cn
package com.fruitshorts.app.service;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.fruitshorts.content.dal.entity.Drama;
import com.fruitshorts.content.dal.mapper.DramaEpisodeMapper;
import com.fruitshorts.content.dal.mapper.DramaMapper;
import com.fruitshorts.content.dal.mapper.DramaReviewRecordMapper;
import com.fruitshorts.content.service.DramaCategoryService;
import com.fruitshorts.content.service.DramaService;
import org.apache.ibatis.builder.MapperBuilderAssistant;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.mockito.ArgumentCaptor;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
/** 收藏数减操作必须使用不低于 0 的原子 SQL。 */
class DramaServiceFavoriteCountTest {
@BeforeAll
static void initTableInfo() {
TableInfoHelper.initTableInfo(
new MapperBuilderAssistant(new MybatisConfiguration(), ""), Drama.class);
}
@Test
@SuppressWarnings("unchecked")
void should_use_greatest_zero_when_favorite_count_decrements() {
DramaMapper dramaMapper = mock(DramaMapper.class);
DramaService dramaService = new DramaService(
dramaMapper,
mock(DramaEpisodeMapper.class),
mock(DramaReviewRecordMapper.class),
mock(DramaCategoryService.class));
given(dramaMapper.update(isNull(), any())).willReturn(1);
ArgumentCaptor<Wrapper<Drama>> captor = ArgumentCaptor.forClass(Wrapper.class);
dramaService.adjustFavoriteCount(7L, -1);
verify(dramaMapper).update(isNull(), captor.capture());
Wrapper<Drama> wrapper = captor.getValue();
LambdaUpdateWrapper<Drama> update = (LambdaUpdateWrapper<Drama>) wrapper;
assertThat(update.getSqlSet())
.contains("GREATEST(favorite_count - 1, 0)");
assertThat(update.getSqlSegment()).contains("id");
}
}
@@ -0,0 +1,80 @@
// Author: fruit.com.cn
package com.fruitshorts.playback.service;
import com.fruitshorts.content.service.DramaService;
import com.fruitshorts.playback.dal.entity.UserFavorite;
import com.fruitshorts.playback.dal.mapper.UserFavoriteMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
/** 收藏关系变化时同步维护短剧收藏数。 */
class FavoriteServiceTest {
private UserFavoriteMapper favoriteMapper;
private DramaService dramaService;
private FavoriteService favoriteService;
@BeforeEach
void setUp() {
favoriteMapper = mock(UserFavoriteMapper.class);
dramaService = mock(DramaService.class);
favoriteService = new FavoriteService(favoriteMapper, dramaService);
}
@Test
void should_increment_favorite_count_when_new_favorite_is_created() {
given(favoriteMapper.selectOne(any())).willReturn(null);
given(favoriteMapper.insert(any(UserFavorite.class))).willReturn(1);
boolean favorite = favoriteService.toggle(1L, 7L);
assertThat(favorite).isTrue();
verify(dramaService).adjustFavoriteCount(7L, 1);
}
@Test
void should_decrement_favorite_count_when_toggle_removes_relation() {
given(favoriteMapper.selectOne(any())).willReturn(new UserFavorite());
given(favoriteMapper.physicalDelete(1L, 7L)).willReturn(1);
boolean favorite = favoriteService.toggle(1L, 7L);
assertThat(favorite).isFalse();
verify(dramaService).adjustFavoriteCount(7L, -1);
}
@Test
void should_only_decrement_when_remove_actually_deletes_relation() {
given(favoriteMapper.physicalDelete(1L, 7L)).willReturn(1);
given(favoriteMapper.physicalDelete(1L, 8L)).willReturn(0);
favoriteService.remove(1L, 7L);
favoriteService.remove(1L, 8L);
verify(dramaService).adjustFavoriteCount(7L, -1);
verify(dramaService, never()).adjustFavoriteCount(8L, -1);
}
@Test
void should_decrement_each_deleted_drama_when_batch_remove_is_called() {
given(favoriteMapper.physicalDelete(1L, 7L)).willReturn(1);
given(favoriteMapper.physicalDelete(1L, 8L)).willReturn(0);
given(favoriteMapper.physicalDelete(1L, 9L)).willReturn(1);
favoriteService.removeBatch(1L, Arrays.asList(7L, 8L, 9L, null));
verify(dramaService).adjustFavoriteCount(7L, -1);
verify(dramaService, never()).adjustFavoriteCount(8L, -1);
verify(dramaService).adjustFavoriteCount(9L, -1);
}
}