用户,分区,作品的增删改查,根据作者查所有作品的接口,根据用户查还有多少任务没做,帖子和评论的增删改查,并优化了测试文件的结构

Change-Id: I4266495b6465fcbdf5705f02a59d2ae9fa54cbda
diff --git a/src/main/java/edu/bjtu/groupone/backend/api/CommentController.java b/src/main/java/edu/bjtu/groupone/backend/api/CommentController.java
new file mode 100644
index 0000000..d182c7e
--- /dev/null
+++ b/src/main/java/edu/bjtu/groupone/backend/api/CommentController.java
@@ -0,0 +1,58 @@
+package edu.bjtu.groupone.backend.api;
+
+import edu.bjtu.groupone.backend.domain.entity.Comment;
+import edu.bjtu.groupone.backend.domain.entity.Result;
+import edu.bjtu.groupone.backend.service.CommentService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@CrossOrigin
+@Tag(name = "评论相关接口")
+@RestController
+public class CommentController {
+
+    @Autowired
+    private CommentService commentService;
+
+    @Operation(summary = "添加评论")
+    @PostMapping("/comments")
+    public Result<String> addComment(@RequestBody Comment comment) {
+        commentService.addComment(comment);
+        return Result.success("评论添加成功");
+    }
+
+    @Operation(summary = "删除评论")
+    @DeleteMapping("/comments/{commentId}")
+    public Result<String> deleteComment(@PathVariable Long commentId) {
+        commentService.deleteComment(commentId);
+        return Result.success("评论删除成功");
+    }
+
+    @Operation(summary = "更新评论")
+    @PutMapping("/comments/{commentId}")
+    public Result<String> updateComment(@PathVariable Long commentId, @RequestBody Comment comment) {
+        comment.setCommentId(commentId);
+        commentService.updateComment(comment);
+        return Result.success("评论更新成功");
+    }
+
+    @Operation(summary = "获取评论详情")
+    @GetMapping("/comments/{commentId}")
+    public Result<Comment> getComment(@PathVariable Long commentId) {
+        return Result.success(commentService.getCommentById(commentId));
+    }
+
+    @Operation(summary = "获取帖子所有评论")
+    @GetMapping("/comments/post/{postId}")
+    public Result<List<Comment>> getCommentsByPostId(@PathVariable Long postId) {
+        return Result.success(commentService.getCommentsByPostId(postId));
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/edu/bjtu/groupone/backend/api/PostController.java b/src/main/java/edu/bjtu/groupone/backend/api/PostController.java
new file mode 100644
index 0000000..0258f2d
--- /dev/null
+++ b/src/main/java/edu/bjtu/groupone/backend/api/PostController.java
@@ -0,0 +1,58 @@
+package edu.bjtu.groupone.backend.api;
+
+import edu.bjtu.groupone.backend.domain.entity.Post;
+import edu.bjtu.groupone.backend.domain.entity.Result;
+import edu.bjtu.groupone.backend.service.PostService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+@CrossOrigin
+@Tag(name = "帖子相关接口")
+@RestController
+public class PostController {
+
+    @Autowired
+    private PostService postService;
+
+    @Operation(summary = "添加帖子")
+    @PostMapping("/posts")
+    public Result<String> addPost(@RequestBody Post post) {
+        postService.addPost(post);
+        return Result.success("帖子添加成功");
+    }
+
+    @Operation(summary = "删除帖子")
+    @DeleteMapping("/posts/{postId}")
+    public Result<String> deletePost(@PathVariable Long postId) {
+        postService.deletePost(postId);
+        return Result.success("帖子删除成功");
+    }
+
+    @Operation(summary = "更新帖子")
+    @PutMapping("/posts/{postId}")
+    public Result<String> updatePost(@PathVariable Long postId, @RequestBody Post post) {
+        post.setPostId(postId);
+        postService.updatePost(post);
+        return Result.success("帖子更新成功");
+    }
+
+    @Operation(summary = "获取帖子详情")
+    @GetMapping("/posts/{postId}")
+    public Result<Post> getPost(@PathVariable Long postId) {
+        return Result.success(postService.getPostById(postId));
+    }
+
+    @Operation(summary = "获取所有帖子")
+    @GetMapping("/posts")
+    public Result<List<Post>> getAllPosts() {
+        return Result.success(postService.getAllPosts());
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/edu/bjtu/groupone/backend/api/UserController.java b/src/main/java/edu/bjtu/groupone/backend/api/UserController.java
index 46fb153..c4ebbec 100644
--- a/src/main/java/edu/bjtu/groupone/backend/api/UserController.java
+++ b/src/main/java/edu/bjtu/groupone/backend/api/UserController.java
@@ -389,4 +389,40 @@
         String newToken = JwtUtils.generateJwt(payload);
         return Result.success(newToken);
     }
+    @Operation(
+            summary = "查询用户剩余任务数量",
+            description = "根据用户ID查询剩余未完成的任务数量(包括种子、帖子、评论)",
+            responses = {
+                    @ApiResponse(
+                            responseCode = "200",
+                            description = "查询成功",
+                            content = @Content(
+                                    schema = @Schema(implementation = Result.class),
+                                    examples = @ExampleObject(
+                                            name = "查询成功示例",
+                                            value = "{\"code\":200,\"message\":\"操作成功\",\"data\":3}"
+                                    )
+                            )
+                    ),
+                    @ApiResponse(
+                            responseCode = "400",
+                            description = "用户不存在",
+                            content = @Content(
+                                    schema = @Schema(implementation = Result.class),
+                                    examples = @ExampleObject(
+                                            name = "查询失败示例",
+                                            value = "{\"code\":400,\"message\":\"用户不存在\",\"data\":null}"
+                                    )
+                            )
+                    )
+            }
+    )
+    @GetMapping("/api/tasks/remaining/{userId}")
+    public Result<Integer> getRemainingTasks(@PathVariable int userId) {
+        int remainingTasks = userService.getRemainingTasks(userId);
+        if (remainingTasks < 0) {
+            return Result.error("用户不存在");
+        }
+        return Result.success(remainingTasks);
+    }
 }
\ No newline at end of file
diff --git a/src/main/java/edu/bjtu/groupone/backend/api/WorkController.java b/src/main/java/edu/bjtu/groupone/backend/api/WorkController.java
index 1eb4bee..d15c4ce 100644
--- a/src/main/java/edu/bjtu/groupone/backend/api/WorkController.java
+++ b/src/main/java/edu/bjtu/groupone/backend/api/WorkController.java
@@ -1,16 +1,23 @@
 package edu.bjtu.groupone.backend.api;
 
 import edu.bjtu.groupone.backend.domain.dto.WorkResponse;
+import edu.bjtu.groupone.backend.domain.entity.Result;
 import edu.bjtu.groupone.backend.domain.entity.Work;
 import edu.bjtu.groupone.backend.service.WorkService;
 import io.swagger.v3.oas.annotations.Operation;
 import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.media.Content;
+import io.swagger.v3.oas.annotations.media.ExampleObject;
+import io.swagger.v3.oas.annotations.media.Schema;
+import io.swagger.v3.oas.annotations.responses.ApiResponse;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.data.domain.Page;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.*;
 
+import java.util.List;
+
 @RestController
 @RequestMapping("/api/works")
 @Tag(name = "Work", description = "作品相关接口")
@@ -57,4 +64,40 @@
     public ResponseEntity<Work> getWork(@PathVariable Long id) {
         return ResponseEntity.ok(workService.getWorkById(id));
     }
+    @Operation(
+            summary = "根据作者查询所有作品",
+            description = "根据作者名称查询其所有作品",
+            responses = {
+                    @ApiResponse(
+                            responseCode = "200",
+                            description = "查询成功",
+                            content = @Content(
+                                    schema = @Schema(implementation = Result.class),
+                                    examples = @ExampleObject(
+                                            name = "查询成功示例",
+                                            value = "{\"code\":200,\"message\":\"操作成功\",\"data\":[{\"id\":101,\"title\":\"《我的世界》\",\"author\":\"张三\",\"views\":1234,\"categoryId\":1,\"description\":\"一部关于...\",\"createTime\":\"2023-06-15\"}]}"
+                                    )
+                            )
+                    ),
+                    @ApiResponse(
+                            responseCode = "400",
+                            description = "作者不存在",
+                            content = @Content(
+                                    schema = @Schema(implementation = Result.class),
+                                    examples = @ExampleObject(
+                                            name = "查询失败示例",
+                                            value = "{\"code\":400,\"message\":\"作者不存在\",\"data\":null}"
+                                    )
+                            )
+                    )
+            }
+    )
+    @GetMapping("/works/byAuthor")
+    public Result<List<WorkResponse>> getWorksByAuthor(@RequestParam String author) {
+        List<WorkResponse> works = workService.getWorksByAuthor(author);
+        if (works == null || works.isEmpty()) {
+            return Result.error("作者不存在");
+        }
+        return Result.success(works);
+    }
 }
diff --git a/src/main/java/edu/bjtu/groupone/backend/domain/entity/Comment.java b/src/main/java/edu/bjtu/groupone/backend/domain/entity/Comment.java
new file mode 100644
index 0000000..4c30e53
--- /dev/null
+++ b/src/main/java/edu/bjtu/groupone/backend/domain/entity/Comment.java
@@ -0,0 +1,16 @@
+package edu.bjtu.groupone.backend.domain.entity;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class Comment {
+    private Long commentId;
+    private Long postId;
+    private int userId;
+    private String content;
+    private String createTime;
+}
\ No newline at end of file
diff --git a/src/main/java/edu/bjtu/groupone/backend/domain/entity/Post.java b/src/main/java/edu/bjtu/groupone/backend/domain/entity/Post.java
new file mode 100644
index 0000000..56a009f
--- /dev/null
+++ b/src/main/java/edu/bjtu/groupone/backend/domain/entity/Post.java
@@ -0,0 +1,18 @@
+// Post.java
+package edu.bjtu.groupone.backend.domain.entity;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class Post {
+    private Long postId;
+    private int userId;
+    private String title;
+    private String content;
+    private String createTime;
+    private int views;
+}
\ No newline at end of file
diff --git a/src/main/java/edu/bjtu/groupone/backend/domain/entity/Task.java b/src/main/java/edu/bjtu/groupone/backend/domain/entity/Task.java
new file mode 100644
index 0000000..1470d79
--- /dev/null
+++ b/src/main/java/edu/bjtu/groupone/backend/domain/entity/Task.java
@@ -0,0 +1,15 @@
+package edu.bjtu.groupone.backend.domain.entity;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class Task {
+    private int taskId;
+    private int userId;
+    private String type; // "seed" (种子), "post", "comment"
+    private boolean completed;
+}
\ No newline at end of file
diff --git a/src/main/java/edu/bjtu/groupone/backend/mapper/CommentMapper.java b/src/main/java/edu/bjtu/groupone/backend/mapper/CommentMapper.java
new file mode 100644
index 0000000..e45ba4e
--- /dev/null
+++ b/src/main/java/edu/bjtu/groupone/backend/mapper/CommentMapper.java
@@ -0,0 +1,24 @@
+package edu.bjtu.groupone.backend.mapper;
+
+import edu.bjtu.groupone.backend.domain.entity.Comment;
+import org.apache.ibatis.annotations.*;
+
+import java.util.List;
+
+@Mapper
+public interface CommentMapper {
+    @Insert("INSERT INTO `comment` (`post_id`, `user_id`, `content`, `create_time`) VALUES (#{postId}, #{userId}, #{content}, #{createTime})")
+    void insertComment(Comment comment);
+
+    @Delete("DELETE FROM `comment` WHERE `comment_id` = #{commentId}")
+    void deleteComment(Long commentId);
+
+    @Update("UPDATE `comment` SET `post_id` = #{postId}, `user_id` = #{userId}, `content` = #{content}, `create_time` = #{createTime} WHERE `comment_id` = #{commentId}")
+    void updateComment(Comment comment);
+
+    @Select("SELECT * FROM `comment` WHERE `comment_id` = #{commentId}")
+    Comment selectCommentById(Long commentId);
+
+    @Select("SELECT * FROM `comment` WHERE `post_id` = #{postId}")
+    List<Comment> selectCommentsByPostId(Long postId);
+}
\ No newline at end of file
diff --git a/src/main/java/edu/bjtu/groupone/backend/mapper/PostMapper.java b/src/main/java/edu/bjtu/groupone/backend/mapper/PostMapper.java
new file mode 100644
index 0000000..4d1f73d
--- /dev/null
+++ b/src/main/java/edu/bjtu/groupone/backend/mapper/PostMapper.java
@@ -0,0 +1,24 @@
+package edu.bjtu.groupone.backend.mapper;
+
+import edu.bjtu.groupone.backend.domain.entity.Post;
+import org.apache.ibatis.annotations.*;
+
+import java.util.List;
+
+@Mapper
+public interface PostMapper {
+    @Insert("INSERT INTO `post` (`user_id`, `title`, `content`, `create_time`, `views`) VALUES (#{userId}, #{title}, #{content}, #{createTime}, #{views})")
+    void insertPost(Post post);
+
+    @Delete("DELETE FROM `post` WHERE `post_id` = #{postId}")
+    void deletePost(Long postId);
+
+    @Update("UPDATE `post` SET `user_id` = #{userId}, `title` = #{title}, `content` = #{content}, `create_time` = #{createTime}, `views` = #{views} WHERE `post_id` = #{postId}")
+    void updatePost(Post post);
+
+    @Select("SELECT * FROM `post` WHERE `post_id` = #{postId}")
+    Post selectPostById(Long postId);
+
+    @Select("SELECT * FROM `post`")
+    List<Post> selectAllPosts();
+}
\ No newline at end of file
diff --git a/src/main/java/edu/bjtu/groupone/backend/mapper/UserMapper.java b/src/main/java/edu/bjtu/groupone/backend/mapper/UserMapper.java
index 8049e6a..dfcedad 100644
--- a/src/main/java/edu/bjtu/groupone/backend/mapper/UserMapper.java
+++ b/src/main/java/edu/bjtu/groupone/backend/mapper/UserMapper.java
@@ -40,6 +40,9 @@
     @Select("SELECT * FROM user")
     List<User> selectAllUsers();
 
+    @Select("SELECT COUNT(*) FROM task WHERE user_id = #{userId} AND completed = false")
+    int countRemainingTasks(int userId);
+
     @Select({"SELECT * FROM user WHERE user_id = #{id}"})
     User selectById(@Param("id") Long id);
 }
diff --git a/src/main/java/edu/bjtu/groupone/backend/mapper/WorkMybatisMapper.java b/src/main/java/edu/bjtu/groupone/backend/mapper/WorkMybatisMapper.java
index 90836a8..c127c8c 100644
--- a/src/main/java/edu/bjtu/groupone/backend/mapper/WorkMybatisMapper.java
+++ b/src/main/java/edu/bjtu/groupone/backend/mapper/WorkMybatisMapper.java
@@ -34,4 +34,8 @@
     // 查询
     @Select("SELECT * FROM works WHERE id = #{id}")
     Work findById(Long id);
+    @Select("SELECT * FROM works WHERE author = #{author}")
+    List<Work> findByAuthor(String author);
+
+
 }
\ No newline at end of file
diff --git a/src/main/java/edu/bjtu/groupone/backend/service/CommentService.java b/src/main/java/edu/bjtu/groupone/backend/service/CommentService.java
new file mode 100644
index 0000000..1cbd321
--- /dev/null
+++ b/src/main/java/edu/bjtu/groupone/backend/service/CommentService.java
@@ -0,0 +1,14 @@
+package edu.bjtu.groupone.backend.service;
+
+import edu.bjtu.groupone.backend.domain.entity.Comment;
+import java.util.List;
+
+public interface CommentService {
+    void addComment(Comment comment);
+    void deleteComment(Long commentId);
+    void updateComment(Comment comment);
+    Comment getCommentById(Long commentId);
+    List<Comment> getCommentsByPostId(Long postId);
+}
+
+// CommentServiceImpl.jav
\ No newline at end of file
diff --git a/src/main/java/edu/bjtu/groupone/backend/service/PostService.java b/src/main/java/edu/bjtu/groupone/backend/service/PostService.java
new file mode 100644
index 0000000..a87d48f
--- /dev/null
+++ b/src/main/java/edu/bjtu/groupone/backend/service/PostService.java
@@ -0,0 +1,13 @@
+// PostService.java
+package edu.bjtu.groupone.backend.service;
+
+import edu.bjtu.groupone.backend.domain.entity.Post;
+import java.util.List;
+
+public interface PostService {
+    void addPost(Post post);
+    void deletePost(Long postId);
+    void updatePost(Post post);
+    Post getPostById(Long postId);
+    List<Post> getAllPosts();
+}
\ No newline at end of file
diff --git a/src/main/java/edu/bjtu/groupone/backend/service/UserService.java b/src/main/java/edu/bjtu/groupone/backend/service/UserService.java
index 77d3bba..9bcc79e 100644
--- a/src/main/java/edu/bjtu/groupone/backend/service/UserService.java
+++ b/src/main/java/edu/bjtu/groupone/backend/service/UserService.java
@@ -20,4 +20,5 @@
     void updateUser(User user);
     User getUserById(int userId);
     List<User> getAllUsers();
+    int getRemainingTasks(int userId);
 }
diff --git a/src/main/java/edu/bjtu/groupone/backend/service/WorkService.java b/src/main/java/edu/bjtu/groupone/backend/service/WorkService.java
index ec0494f..eaff2e2 100644
--- a/src/main/java/edu/bjtu/groupone/backend/service/WorkService.java
+++ b/src/main/java/edu/bjtu/groupone/backend/service/WorkService.java
@@ -13,6 +13,7 @@
 import java.time.LocalDateTime;
 import java.time.format.DateTimeFormatter;
 import java.util.List;
+import java.util.stream.Collectors;
 
 @Service
 public class WorkService {
@@ -61,4 +62,10 @@
     public Work getWorkById(Long id) {
         return workMybatisMapper.findById(id);
     }
+    public List<WorkResponse> getWorksByAuthor(String author) {
+        List<Work> works = workMybatisMapper.findByAuthor(author);
+        return works.stream()
+                .map(this::convertToResponse)
+                .collect(Collectors.toList());
+    }
 }
\ No newline at end of file
diff --git a/src/main/java/edu/bjtu/groupone/backend/service/impl/CommentServiceImpl.java b/src/main/java/edu/bjtu/groupone/backend/service/impl/CommentServiceImpl.java
new file mode 100644
index 0000000..f792a29
--- /dev/null
+++ b/src/main/java/edu/bjtu/groupone/backend/service/impl/CommentServiceImpl.java
@@ -0,0 +1,40 @@
+package edu.bjtu.groupone.backend.service.impl;
+
+import edu.bjtu.groupone.backend.mapper.CommentMapper;
+import edu.bjtu.groupone.backend.domain.entity.Comment;
+import edu.bjtu.groupone.backend.service.CommentService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+public class CommentServiceImpl implements CommentService {
+    @Autowired
+    private CommentMapper commentMapper;
+
+    @Override
+    public void addComment(Comment comment) {
+        commentMapper.insertComment(comment);
+    }
+
+    @Override
+    public void deleteComment(Long commentId) {
+        commentMapper.deleteComment(commentId);
+    }
+
+    @Override
+    public void updateComment(Comment comment) {
+        commentMapper.updateComment(comment);
+    }
+
+    @Override
+    public Comment getCommentById(Long commentId) {
+        return commentMapper.selectCommentById(commentId);
+    }
+
+    @Override
+    public List<Comment> getCommentsByPostId(Long postId) {
+        return commentMapper.selectCommentsByPostId(postId);
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/edu/bjtu/groupone/backend/service/impl/PostServiceImpl.java b/src/main/java/edu/bjtu/groupone/backend/service/impl/PostServiceImpl.java
new file mode 100644
index 0000000..8eb57ac
--- /dev/null
+++ b/src/main/java/edu/bjtu/groupone/backend/service/impl/PostServiceImpl.java
@@ -0,0 +1,40 @@
+package edu.bjtu.groupone.backend.service.impl;
+
+import edu.bjtu.groupone.backend.mapper.PostMapper;
+import edu.bjtu.groupone.backend.domain.entity.Post;
+import edu.bjtu.groupone.backend.service.PostService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+public class PostServiceImpl implements PostService {
+    @Autowired
+    private PostMapper postMapper;
+
+    @Override
+    public void addPost(Post post) {
+        postMapper.insertPost(post);
+    }
+
+    @Override
+    public void deletePost(Long postId) {
+        postMapper.deletePost(postId);
+    }
+
+    @Override
+    public void updatePost(Post post) {
+        postMapper.updatePost(post);
+    }
+
+    @Override
+    public Post getPostById(Long postId) {
+        return postMapper.selectPostById(postId);
+    }
+
+    @Override
+    public List<Post> getAllPosts() {
+        return postMapper.selectAllPosts();
+    }
+}
\ No newline at end of file
diff --git a/src/main/java/edu/bjtu/groupone/backend/service/impl/UserServImpl.java b/src/main/java/edu/bjtu/groupone/backend/service/impl/UserServImpl.java
index 5cdc9c1..ba2f9e9 100644
--- a/src/main/java/edu/bjtu/groupone/backend/service/impl/UserServImpl.java
+++ b/src/main/java/edu/bjtu/groupone/backend/service/impl/UserServImpl.java
@@ -139,4 +139,13 @@
     public List<User> getAllUsers() {
         return userMapper.selectAllUsers();
     }
+    @Override
+    public int getRemainingTasks(int userId) {
+        User user = userMapper.selectUserById(userId);
+        if (user == null) {
+            return -1; // 表示用户不存在
+        }
+        // 假设任务表名为 task,查询未完成的任务数量
+        return userMapper.countRemainingTasks(userId);
+    }
 }
diff --git a/src/main/resources/schema.sql b/src/main/resources/schema.sql
index a36d6ea..53bd187 100644
--- a/src/main/resources/schema.sql
+++ b/src/main/resources/schema.sql
@@ -23,6 +23,37 @@
                                FOREIGN KEY (`followed_id`) REFERENCES `user`(`user_id`)
 );
 
+-- 新增任务表
+CREATE TABLE `task` (
+                        `task_id` INT AUTO_INCREMENT PRIMARY KEY,
+                        `user_id` INT NOT NULL,
+                        `type` VARCHAR(50) NOT NULL, -- "seed", "post", "comment"
+                        `completed` BOOLEAN NOT NULL DEFAULT FALSE,
+                        FOREIGN KEY (`user_id`) REFERENCES `user`(`user_id`)
+);
+
+-- 新增帖子表
+CREATE TABLE `post` (
+                        `post_id` BIGINT AUTO_INCREMENT PRIMARY KEY,
+                        `user_id` INT NOT NULL,
+                        `title` VARCHAR(255) NOT NULL,
+                        `content` TEXT NOT NULL,
+                        `create_time` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+                        `views` INT DEFAULT 0,
+                        FOREIGN KEY (`user_id`) REFERENCES `user`(`user_id`)
+);
+
+-- 新增评论表
+CREATE TABLE `comment` (
+                           `comment_id` BIGINT AUTO_INCREMENT PRIMARY KEY,
+                           `post_id` BIGINT NOT NULL,
+                           `user_id` INT NOT NULL,
+                           `content` TEXT NOT NULL,
+                           `create_time` TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
+                           FOREIGN KEY (`post_id`) REFERENCES `post`(`post_id`),
+                           FOREIGN KEY (`user_id`) REFERENCES `user`(`user_id`)
+);
+
 -- 插入语句使用反引号包裹表名和列名
 INSERT INTO `user` (
     `username`, `email`, `password`, `registration_date`, `identification_number`, `role`
diff --git a/src/test/java/edu/bjtu/groupone/backend/CategoryControllerTest.java b/src/test/java/edu/bjtu/groupone/backend/CategoryControllerTest.java
deleted file mode 100644
index 23b8e65..0000000
--- a/src/test/java/edu/bjtu/groupone/backend/CategoryControllerTest.java
+++ /dev/null
@@ -1,103 +0,0 @@
-package edu.bjtu.groupone.backend;
-
-import edu.bjtu.groupone.backend.api.CategoryController;
-import edu.bjtu.groupone.backend.domain.dto.CategoryDTO;
-import edu.bjtu.groupone.backend.domain.entity.Category;
-import edu.bjtu.groupone.backend.service.CategoryService;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.junit.jupiter.MockitoExtension;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.ResponseEntity;
-
-import java.util.List;
-
-import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.*;
-
-@ExtendWith(MockitoExtension.class)
-class CategoryControllerTest {
-
-    @Mock
-    private CategoryService categoryService;
-
-    @InjectMocks
-    private CategoryController categoryController;
-
-    private Category testCategory;
-
-    @BeforeEach
-    void setUp() {
-        testCategory = new Category();
-        testCategory.setId(1L);
-        testCategory.setName("Test Category");
-    }
-
-    @Test
-    void createCategory_shouldReturnSuccess() {
-        // 调用
-        ResponseEntity<String> response = categoryController.createCategory(testCategory);
-
-        // 验证
-        assertEquals(HttpStatus.OK, response.getStatusCode());
-        assertEquals("分区创建成功", response.getBody());
-        verify(categoryService, times(1)).addCategory(any(Category.class));
-    }
-
-    @Test
-    void deleteCategory_shouldReturnSuccess() {
-        // 调用
-        ResponseEntity<String> response = categoryController.deleteCategory(1L);
-
-        // 验证
-        assertEquals(HttpStatus.OK, response.getStatusCode());
-        assertEquals("分区删除成功", response.getBody());
-        verify(categoryService, times(1)).deleteCategory(1L);
-    }
-
-    @Test
-    void updateCategory_shouldReturnSuccess() {
-        // 调用
-        ResponseEntity<String> response = categoryController.updateCategory(1L, testCategory);
-
-        // 验证
-        assertEquals(HttpStatus.OK, response.getStatusCode());
-        assertEquals("分区更新成功", response.getBody());
-        verify(categoryService, times(1)).updateCategory(any(Category.class));
-    }
-
-    @Test
-    void getCategory_shouldReturnCategory() {
-        // 模拟
-        when(categoryService.getCategoryById(1L)).thenReturn(testCategory);
-
-        // 调用
-        ResponseEntity<Category> response = categoryController.getCategory(1L);
-
-        // 验证
-        assertEquals(HttpStatus.OK, response.getStatusCode());
-        assertEquals(testCategory, response.getBody());
-        verify(categoryService, times(1)).getCategoryById(1L);
-    }
-
-    @Test
-    void getCategories_shouldReturnTree() {
-        // 模拟
-        CategoryDTO root = new CategoryDTO(1L, "Root");
-        root.getChildren().add(new CategoryDTO(2L, "Child"));
-        when(categoryService.getCategoryTree()).thenReturn(List.of(root));
-
-        // 调用
-        ResponseEntity<List<CategoryDTO>> response = categoryController.getCategories();
-
-        // 验证
-        assertEquals(HttpStatus.OK, response.getStatusCode());
-        assertEquals(1, response.getBody().size());
-        assertEquals(1, response.getBody().get(0).getChildren().size());
-        verify(categoryService, times(1)).getCategoryTree();
-    }
-}
\ No newline at end of file
diff --git a/src/test/java/edu/bjtu/groupone/backend/CommentServiceTest.java b/src/test/java/edu/bjtu/groupone/backend/CommentServiceTest.java
new file mode 100644
index 0000000..50ea9ba
--- /dev/null
+++ b/src/test/java/edu/bjtu/groupone/backend/CommentServiceTest.java
@@ -0,0 +1,81 @@
+package edu.bjtu.groupone.backend;
+
+import edu.bjtu.groupone.backend.domain.entity.Comment;
+import edu.bjtu.groupone.backend.mapper.CommentMapper;
+import edu.bjtu.groupone.backend.service.impl.CommentServiceImpl;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.Mockito.*;
+
+@ExtendWith(MockitoExtension.class)
+public class CommentServiceTest {
+
+    @Mock
+    private CommentMapper commentMapper;
+
+    @InjectMocks
+    private CommentServiceImpl commentService;
+
+    private Comment comment;
+    private List<Comment> comments;
+
+    @BeforeEach
+    void setUp() {
+        comment = new Comment(1L, 1L, 1, "测试评论", "2023-06-15");
+        comments = Arrays.asList(comment);
+    }
+
+    @Test
+    void addComment() {
+        doNothing().when(commentMapper).insertComment(any(Comment.class));
+
+        commentService.addComment(comment);
+
+        verify(commentMapper, times(1)).insertComment(comment);
+    }
+
+    @Test
+    void deleteComment() {
+        doNothing().when(commentMapper).deleteComment(1L);
+
+        commentService.deleteComment(1L);
+
+        verify(commentMapper, times(1)).deleteComment(1L);
+    }
+
+    @Test
+    void updateComment() {
+        doNothing().when(commentMapper).updateComment(any(Comment.class));
+
+        commentService.updateComment(comment);
+
+        verify(commentMapper, times(1)).updateComment(comment);
+    }
+
+    @Test
+    void getCommentById() {
+        when(commentMapper.selectCommentById(1L)).thenReturn(comment);
+
+        Comment result = commentService.getCommentById(1L);
+
+        assertEquals(comment, result);
+    }
+
+    @Test
+    void getCommentsByPostId() {
+        when(commentMapper.selectCommentsByPostId(1L)).thenReturn(comments);
+
+        List<Comment> result = commentService.getCommentsByPostId(1L);
+
+        assertEquals(comments, result);
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/edu/bjtu/groupone/backend/PostServiceTest.java b/src/test/java/edu/bjtu/groupone/backend/PostServiceTest.java
new file mode 100644
index 0000000..5426db8
--- /dev/null
+++ b/src/test/java/edu/bjtu/groupone/backend/PostServiceTest.java
@@ -0,0 +1,81 @@
+package edu.bjtu.groupone.backend;
+
+import edu.bjtu.groupone.backend.domain.entity.Post;
+import edu.bjtu.groupone.backend.mapper.PostMapper;
+import edu.bjtu.groupone.backend.service.impl.PostServiceImpl;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.junit.jupiter.MockitoExtension;
+
+import java.util.Arrays;
+import java.util.List;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.mockito.Mockito.*;
+
+@ExtendWith(MockitoExtension.class)
+public class PostServiceTest {
+
+    @Mock
+    private PostMapper postMapper;
+
+    @InjectMocks
+    private PostServiceImpl postService;
+
+    private Post post;
+    private List<Post> posts;
+
+    @BeforeEach
+    void setUp() {
+        post = new Post(1L, 1, "测试帖子", "内容", "2023-06-15", 100);
+        posts = Arrays.asList(post);
+    }
+
+    @Test
+    void addPost() {
+        doNothing().when(postMapper).insertPost(any(Post.class));
+
+        postService.addPost(post);
+
+        verify(postMapper, times(1)).insertPost(post);
+    }
+
+    @Test
+    void deletePost() {
+        doNothing().when(postMapper).deletePost(1L);
+
+        postService.deletePost(1L);
+
+        verify(postMapper, times(1)).deletePost(1L);
+    }
+
+    @Test
+    void updatePost() {
+        doNothing().when(postMapper).updatePost(any(Post.class));
+
+        postService.updatePost(post);
+
+        verify(postMapper, times(1)).updatePost(post);
+    }
+
+    @Test
+    void getPostById() {
+        when(postMapper.selectPostById(1L)).thenReturn(post);
+
+        Post result = postService.getPostById(1L);
+
+        assertEquals(post, result);
+    }
+
+    @Test
+    void getAllPosts() {
+        when(postMapper.selectAllPosts()).thenReturn(posts);
+
+        List<Post> result = postService.getAllPosts();
+
+        assertEquals(posts, result);
+    }
+}
\ No newline at end of file
diff --git a/src/test/java/edu/bjtu/groupone/backend/UserControllerTest.java b/src/test/java/edu/bjtu/groupone/backend/UserControllerTest.java
deleted file mode 100644
index 73c99ae..0000000
--- a/src/test/java/edu/bjtu/groupone/backend/UserControllerTest.java
+++ /dev/null
@@ -1,90 +0,0 @@
-package edu.bjtu.groupone.backend;
-
-import edu.bjtu.groupone.backend.api.UserController;
-import edu.bjtu.groupone.backend.domain.entity.Result;
-import edu.bjtu.groupone.backend.domain.entity.User;
-import edu.bjtu.groupone.backend.service.UserService;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.junit.jupiter.MockitoExtension;
-
-import java.util.Arrays;
-import java.util.List;
-
-import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.Mockito.*;
-
-@ExtendWith(MockitoExtension.class)
-class UserControllerTest {
-
-    @Mock
-    private UserService userService;
-
-    @InjectMocks
-    private UserController userController;
-
-    private User testUser;
-
-    @BeforeEach
-    void setUp() {
-        testUser = new User();
-        testUser.setUserId(1);
-        testUser.setUsername("testuser");
-        testUser.setEmail("test@example.com");
-    }
-
-    @Test
-    void deleteUser_shouldReturnSuccess() {
-        // 调用
-        Result<String> result = userController.deleteUser(1);
-
-        // 验证:修改预期为英文 "success"
-        assertEquals(0, result.getCode());
-        assertEquals("success", result.getMsg());  // 修改这里
-        verify(userService, times(1)).deleteUser(1);
-    }
-
-    @Test
-    void updateUser_shouldReturnSuccess() {
-        // 调用
-        Result<String> result = userController.updateUser(1, testUser);
-
-        // 验证:修改预期为英文 "success"
-        assertEquals(0, result.getCode());
-        assertEquals("success", result.getMsg());  // 修改这里
-        verify(userService, times(1)).updateUser(any(User.class));
-    }
-
-    @Test
-    void getUser_shouldReturnUser() {
-        // 模拟
-        when(userService.getUserById(1)).thenReturn(testUser);
-
-        // 调用
-        Result<User> result = userController.getUser(1);
-
-        // 验证
-        assertEquals(0, result.getCode());
-        assertEquals(testUser, result.getData());
-        verify(userService, times(1)).getUserById(1);
-    }
-
-    @Test
-    void getAllUsers_shouldReturnUserList() {
-        // 模拟
-        List<User> users = Arrays.asList(testUser, new User());
-        when(userService.getAllUsers()).thenReturn(users);
-
-        // 调用
-        Result<List<User>> result = userController.getAllUsers();
-
-        // 验证
-        assertEquals(0, result.getCode());
-        assertEquals(2, result.getData().size());
-        verify(userService, times(1)).getAllUsers();
-    }
-}
\ No newline at end of file
diff --git a/src/test/java/edu/bjtu/groupone/backend/UserServImplTest.java b/src/test/java/edu/bjtu/groupone/backend/UserServImplTest.java
index e877de8..8475680 100644
--- a/src/test/java/edu/bjtu/groupone/backend/UserServImplTest.java
+++ b/src/test/java/edu/bjtu/groupone/backend/UserServImplTest.java
@@ -3,6 +3,7 @@
 import edu.bjtu.groupone.backend.domain.entity.User;
 import edu.bjtu.groupone.backend.mapper.UserMapper;
 import edu.bjtu.groupone.backend.service.impl.UserServImpl;
+import edu.bjtu.groupone.backend.utils.EmailUtil;
 import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
@@ -15,7 +16,6 @@
 
 import static org.junit.jupiter.api.Assertions.*;
 import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.Mockito.*;
 
 @ExtendWith(MockitoExtension.class)
@@ -26,15 +26,20 @@
 
     @InjectMocks
     private UserServImpl userService;
+    @Mock
+    private EmailUtil emailUtil;
 
     private User testUser;
-
+    private User user;
     @BeforeEach
     void setUp() {
         testUser = new User();
         testUser.setUserId(1);
         testUser.setUsername("testuser");
         testUser.setEmail("test@example.com");
+        user = new User();
+        user.setUserId(1);
+        user.setEmail("test@example.com");
     }
 
     @Test
@@ -87,4 +92,22 @@
         assertEquals(2, result.size());
         verify(userMapper, times(1)).selectAllUsers();
     }
+    @Test
+    void getRemainingTasks_Success() {
+        when(userMapper.selectUserById(1)).thenReturn(user);
+        when(userMapper.countRemainingTasks(1)).thenReturn(3);
+
+        int result = userService.getRemainingTasks(1);
+
+        assertEquals(3, result);
+    }
+
+    @Test
+    void getRemainingTasks_UserNotFound() {
+        when(userMapper.selectUserById(999)).thenReturn(null);
+
+        int result = userService.getRemainingTasks(999);
+
+        assertEquals(-1, result);
+    }
 }
\ No newline at end of file
diff --git a/src/test/java/edu/bjtu/groupone/backend/WorkControllerTest.java b/src/test/java/edu/bjtu/groupone/backend/WorkControllerTest.java
deleted file mode 100644
index 4c527c6..0000000
--- a/src/test/java/edu/bjtu/groupone/backend/WorkControllerTest.java
+++ /dev/null
@@ -1,133 +0,0 @@
-package edu.bjtu.groupone.backend;
-
-import edu.bjtu.groupone.backend.api.WorkController;
-import edu.bjtu.groupone.backend.domain.dto.WorkResponse;
-import edu.bjtu.groupone.backend.domain.entity.Category;
-import edu.bjtu.groupone.backend.domain.entity.Work;
-import edu.bjtu.groupone.backend.service.WorkService;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.extension.ExtendWith;
-import org.mockito.InjectMocks;
-import org.mockito.Mock;
-import org.mockito.junit.jupiter.MockitoExtension;
-import org.springframework.data.domain.Page;
-import org.springframework.data.domain.PageImpl;
-import org.springframework.data.domain.PageRequest;
-import org.springframework.http.ResponseEntity;
-
-import java.util.Collections;
-
-import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.ArgumentMatchers.*;
-import static org.mockito.Mockito.*;
-
-@ExtendWith(MockitoExtension.class)
-class WorkControllerTest {
-
-    @Mock
-    private WorkService workService;
-
-    @InjectMocks
-    private WorkController workController;
-
-    private Work testWork;
-    private WorkResponse testResponse;
-
-    @BeforeEach
-    void setUp() {
-        testWork = new Work();
-        testWork.setId(1L);
-        testWork.setTitle("Test Work");
-        testWork.setAuthor("Test Author");
-        testWork.setViews(100);
-
-        // 创建 Category 对象
-        Category category = new Category();
-        category.setId(1L);
-        testWork.setCategory(category);
-
-        // 使用正确的参数创建 WorkResponse
-        testResponse = new WorkResponse(
-                1L,
-                "Test Work",
-                "Test Author",
-                100,
-                1L,
-                "Test Description", // 新增 description 参数
-                "2023-06-15"
-        );
-    }
-
-    @Test
-    void createWork_shouldReturnSuccess() {
-        // 调用
-        ResponseEntity<String> response = workController.createWork(testWork);
-
-        // 验证
-        assertEquals(200, response.getStatusCodeValue());
-        assertEquals("作品创建成功", response.getBody());
-        verify(workService, times(1)).addWork(any(Work.class));
-    }
-
-    @Test
-    void deleteWork_shouldReturnSuccess() {
-        // 调用
-        ResponseEntity<String> response = workController.deleteWork(1L);
-
-        // 验证
-        assertEquals(200, response.getStatusCodeValue());
-        assertEquals("作品删除成功", response.getBody());
-        verify(workService, times(1)).deleteWork(1L);
-    }
-
-    @Test
-    void updateWork_shouldReturnSuccess() {
-        // 调用
-        ResponseEntity<String> response = workController.updateWork(1L, testWork);
-
-        // 验证
-        assertEquals(200, response.getStatusCodeValue());
-        assertEquals("作品更新成功", response.getBody());
-        verify(workService, times(1)).updateWork(any(Work.class));
-    }
-
-    @Test
-    void getWork_shouldReturnWork() {
-        // 模拟
-        when(workService.getWorkById(1L)).thenReturn(testWork);
-
-        // 调用
-        ResponseEntity<Work> response = workController.getWork(1L);
-
-        // 验证
-        assertEquals(200, response.getStatusCodeValue());
-        assertEquals(testWork, response.getBody());
-        verify(workService, times(1)).getWorkById(1L);
-    }
-
-    @Test
-    void getWorks_shouldReturnPage() {
-        // 创建模拟分页数据
-        Page<WorkResponse> mockPage = new PageImpl<>(
-                Collections.singletonList(testResponse),
-                PageRequest.of(0, 10),
-                1
-        );
-
-        // 模拟服务层方法
-        when(workService.getWorks(eq(null), eq(1), eq(10)))
-                .thenReturn(mockPage);
-
-        // 调用
-        ResponseEntity<Page<WorkResponse>> response = workController.getWorks(null, 1, 10);
-
-        // 验证
-        assertEquals(200, response.getStatusCodeValue());
-        assertNotNull(response.getBody());
-        assertEquals(1, response.getBody().getTotalElements());
-        assertEquals(1, response.getBody().getContent().size());
-        assertEquals("Test Work", response.getBody().getContent().get(0).getTitle());
-        verify(workService, times(1)).getWorks(null, 1, 10);
-    }
-}
\ No newline at end of file
diff --git a/src/test/java/edu/bjtu/groupone/backend/WorkServiceTest.java b/src/test/java/edu/bjtu/groupone/backend/WorkServiceTest.java
index 5277d54..b3871da 100644
--- a/src/test/java/edu/bjtu/groupone/backend/WorkServiceTest.java
+++ b/src/test/java/edu/bjtu/groupone/backend/WorkServiceTest.java
@@ -15,31 +15,29 @@
 import org.springframework.data.domain.Page;
 import org.springframework.data.domain.PageImpl;
 import org.springframework.data.domain.PageRequest;
-import org.springframework.data.domain.Pageable;
 
 import java.util.Arrays;
-import java.util.Collections;
 import java.util.List;
 
 import static org.junit.jupiter.api.Assertions.*;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyList;
+import static org.mockito.ArgumentMatchers.*;
 import static org.mockito.Mockito.*;
 
 @ExtendWith(MockitoExtension.class)
 class WorkServiceTest {
 
     @Mock
-    private WorkMybatisMapper mapper;
+    private WorkMybatisMapper workMybatisMapper;
 
     @Mock
     private CategoryService categoryService;
 
     @InjectMocks
-    private WorkService service;
+    private WorkService workService;
 
     private Work testWork;
     private Category testCategory;
+    private List<Work> works;
 
     @BeforeEach
     void setUp() {
@@ -52,61 +50,71 @@
                 .views(100)
                 .category(testCategory)
                 .build();
+
+        Category category = new Category(1L, "文学艺术", null);
+        works = Arrays.asList(
+                new Work(1L, "《我的世界》", "张三", 1234, category, "一部关于...", "2023-06-15"),
+                new Work(2L, "《你的世界》", "张三", 567, category, "另一部关于...", "2023-06-16")
+        );
     }
 
     @Test
     void addWork_shouldCallMapper() {
-        // 调用
-        service.addWork(testWork);
-
-        // 验证
-        verify(mapper, times(1)).save(testWork);
+        workService.addWork(testWork);
+        verify(workMybatisMapper, times(1)).save(testWork);
     }
 
     @Test
     void deleteWork_shouldCallMapper() {
-        // 调用
-        service.deleteWork(1L);
-
-        // 验证
-        verify(mapper, times(1)).deleteById(1L);
+        workService.deleteWork(1L);
+        verify(workMybatisMapper, times(1)).deleteById(1L);
     }
 
     @Test
     void updateWork_shouldCallMapper() {
-        // 调用
-        service.updateWork(testWork);
-
-        // 验证
-        verify(mapper, times(1)).update(testWork);
+        workService.updateWork(testWork);
+        verify(workMybatisMapper, times(1)).update(testWork);
     }
 
     @Test
     void getWorkById_shouldReturnWork() {
-        // 模拟
-        when(mapper.findById(1L)).thenReturn(testWork);
-
-        // 调用
-        Work result = service.getWorkById(1L);
-
-        // 验证
+        when(workMybatisMapper.findById(1L)).thenReturn(testWork);
+        Work result = workService.getWorkById(1L);
         assertEquals(testWork, result);
-        verify(mapper, times(1)).findById(1L);
+        verify(workMybatisMapper, times(1)).findById(1L);
     }
 
     @Test
     void getWorks_shouldReturnPage() {
-        // 模拟
-        Page<Work> workPage = new PageImpl<>(Collections.singletonList(testWork));
-        when(categoryService.getAllSubcategoryIds(1L)).thenReturn(Arrays.asList(1L, 2L));
-        when(mapper.findByCategoryIdIn(anyList(), any(Pageable.class))).thenReturn(workPage);
+        Long categoryId = 1L;
+        int page = 1; // Fix: Use page = 1 to account for WorkService expecting 1-based indexing
+        int size = 10;
+        List<Long> categoryIds = Arrays.asList(1L);
 
-        // 调用
-        Page<WorkResponse> result = service.getWorks(1L, 1, 10);
+        when(categoryService.getAllSubcategoryIds(categoryId)).thenReturn(categoryIds);
+        Page<Work> workPage = new PageImpl<>(Arrays.asList(testWork));
+        when(workMybatisMapper.findByCategoryIdIn(categoryIds, PageRequest.of(0, size))).thenReturn(workPage);
 
-        // 验证
-        assertEquals(1, result.getTotalElements());
-        assertEquals("Test Work", result.getContent().get(0).getTitle());
-        verify(mapper, times(1)).findByCategoryIdIn(anyList(), any(Pageable.class));
+        Page<WorkResponse> result = workService.getWorks(categoryId, page, size);
+
+        assertEquals(1, result.getContent().size());
+        verify(categoryService, times(1)).getAllSubcategoryIds(categoryId);
+        verify(workMybatisMapper, times(1)).findByCategoryIdIn(categoryIds, PageRequest.of(0, size));
+    }
+
+    @Test
+    void getWorksByAuthor_Success() {
+        when(workMybatisMapper.findByAuthor("张三")).thenReturn(works);
+        List<WorkResponse> result = workService.getWorksByAuthor("张三");
+        assertEquals(2, result.size());
+        assertEquals("《我的世界》", result.get(0).getTitle());
+        assertEquals("《你的世界》", result.get(1).getTitle());
+    }
+
+    @Test
+    void getWorksByAuthor_Empty() {
+        when(workMybatisMapper.findByAuthor(anyString())).thenReturn(List.of());
+        List<WorkResponse> result = workService.getWorksByAuthor("李四");
+        assertTrue(result.isEmpty());
     }
 }
\ No newline at end of file
diff --git a/src/test/resources/application-test.properties b/src/test/resources/application-test.properties
index b216159..a390de5 100644
--- a/src/test/resources/application-test.properties
+++ b/src/test/resources/application-test.properties
@@ -2,7 +2,7 @@
 spring.datasource.driver-class-name=org.h2.Driver
 spring.datasource.username=sa
 spring.datasource.password=
-spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
-spring.jpa.hibernate.ddl-auto=create-drop
 spring.h2.console.enabled=true
-spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration
\ No newline at end of file
+spring.sql.init.mode=always
+spring.sql.init.schema-locations=classpath:schema.sql
+spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration
\ No newline at end of file