hocvietcode.com
  • Trang chủ
  • Học lập trình
    • Lập trình C/C++
    • Cấu trúc dữ liệu và giải thuật
    • Lập trình HTML
    • Lập trình Javascript
      • Javascript cơ bản
      • ReactJS framework
      • AngularJS framework
      • Typescript cơ bản
      • Angular
      • NodeJS
    • Lập trình Mobile
      • Lập Trình Dart Cơ Bản
        • Dart Flutter Framework
    • Cơ sở dữ liệu
      • MySQL – MariaDB
      • Micrsoft SQL Server
      • Extensible Markup Language (XML)
      • JSON
      • MongoDB
    • Lập trình PHP
      • Lập trình PHP cơ bản
      • Laravel Framework
    • Lập trình Java
      • Java Cơ bản
      • Spring Boot
    • Lập trình C#
      • Lập Trình C# Cơ Bản
      • ASP.NET Core MVC
    • Machine Learning
    • Git và Github
  • WORDPRESS
    • WordPress cơ bản
    • WordPress nâng cao
    • Chia sẻ WordPress
  • Kiến thức hệ thống
    • Microsoft Azure
    • Docker
    • Linux
  • Chia sẻ IT
    • Tin học văn phòng
      • Microsoft Word
      • Microsoft Excel
    • Marketing
      • Google Adwords
      • Facebook Ads
      • Kiến thức khác
    • Chia sẻ phần mềm
    • Review công nghệ
    • Công cụ – tiện ích
      • Kiểm tra bàn phím online
      • Kiểm tra webcam online
  • Lập trình Python
Đăng nhập
  • Đăng nhập / Đăng ký

Please enter key search to display results.

Home
  • Spring Boot
Spring Boot bài 25: Unit test Service với JUnit và Mockito
Java và Spring Boot – MVC và REST API

Spring Boot bài 25: Unit test Service với JUnit và Mockito

  • 18-10-2026
  • Toanngo92
  • 0 Comments

Giáo trình Spring Boot MVC và REST API · Chương 11/12: Kiểm thử Service, MVC và API · Bài 25/28 · Biên soạn tháng 10/2026.

← Bài 24 · Mục lục 12 chương · Bài 26 →

Mục lục

  • Mục tiêu bài học
  • Unit test trả lời câu hỏi nhỏ
  • Arrange, Act, Assert
  • Mock vừa đủ để không khóa chặt implementation
  • Chạy và đọc báo cáo
  • Lỗi thường gặp và lưu ý
  • Ghi nhớ
  • Tài liệu đối chiếu

Mục tiêu bài học

Kiểm tra quy tắc Service bằng mock, chạy nhanh không cần Spring context và chọn hành vi đáng kiểm tra.

Unit test trả lời câu hỏi nhỏ

CourseService cần Repository, nhưng một test quy tắc “không tìm thấy khóa học phải báo lỗi” không cần khởi động web server hoặc MySQL. Mockito tạo đối tượng thay thế cho repository, còn test quyết định dữ liệu trả về. Nhờ constructor injection, Service có thể được tạo và gọi như một class Java bình thường.

JUnit cung cấp vòng đời và assertion/test engine; Mockito hỗ trợ mock; AssertJ giúp viết kỳ vọng dễ đọc. Bộ dependency test theo Spring Boot quản lý các phiên bản tương thích. Không áp đặt một số phiên bản JUnit từ bài cũ vào pom chỉ vì package org.junit.jupiter vẫn có tên quen thuộc.

Tệp trong mã nguồn mẫu: src/test/java/com/hocvietcode/academy/CourseServiceTest.java. Đoạn dưới được trích từ tệp này; xem bản tải về để có đủ import và phần còn lại.

package com.hocvietcode.academy;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.*;
import org.mockito.junit.jupiter.MockitoExtension;
import java.math.BigDecimal;
import java.util.Optional;
import static org.mockito.Mockito.*;
import static org.assertj.core.api.Assertions.*;
@ExtendWith(MockitoExtension.class)
class CourseServiceTest {
    @Mock CourseRepository courses; @Mock CategoryRepository categories;
    @InjectMocks CourseService service;
    @Test void missingCourseHasDomainError(){
        when(courses.findById(99L)).thenReturn(Optional.empty());
        assertThatThrownBy(()->service.get(99L)).isInstanceOf(CourseNotFound.class);
    }
    @Test void invalidPageDoesNotQueryDatabase(){
        assertThatThrownBy(()->service.search("",0,51,"id")).isInstanceOf(IllegalArgumentException.class);
        verifyNoInteractions(courses);
    }
    @Test void updateChangesManagedEntity(){
        Category c=new Category("Java"); Course existing=new Course("Old",BigDecimal.ZERO,c);
        when(courses.findById(1L)).thenReturn(Optional.of(existing));when(categories.findById(1L)).thenReturn(Optional.of(c));
        CourseForm f=new CourseForm();f.setTitle("New title");f.setPrice(new BigDecimal("100.00"));f.setCategoryId(1L);
        assertThat(service.update(1L,f).title()).isEqualTo("New title");
        assertThat(existing.getPrice()).isEqualByComparingTo("100.00");
    }
}

Arrange, Act, Assert

Arrange chuẩn bị đầu vào và hành vi mock; Act gọi phương thức cần kiểm tra; Assert xác nhận kết quả hoặc lỗi. Test missingCourseHasDomainError thiết lập repository không có id rồi mong CourseNotFound. Test invalidPageDoesNotQueryDatabase kiểm tra đầu vào size vượt giới hạn bị từ chối trước truy vấn.

Test updateChangesManagedEntity xác nhận các giá trị nghiệp vụ được đổi đúng. Nó không cố chứng minh Hibernate dirty checking hoạt động, vì ở đây repository là mock và không có persistence context thật. Phần đó thuộc kiểm thử tích hợp với database.

Mock vừa đủ để không khóa chặt implementation

Không cần verify mọi dòng getter/setter hoặc mọi lời gọi nội bộ chỉ vì có thể. Kiểm tra hành vi quan trọng như từ chối đầu vào, lỗi tài nguyên thiếu và kết quả cập nhật có giá trị hơn việc test một phương thức chỉ để đếm số lần nó được gọi.

Mock không thay cho ràng buộc DB, SQL hay transaction. Một test pass với thenReturn có thể che tên truy vấn sai nếu không có test tích hợp bổ sung. Mỗi tầng test nên có mục đích rõ ràng: unit cho quy tắc cô lập, integration cho cách các thành phần kết nối.

Chạy và đọc báo cáo

Tại thư mục chứa pom.xml, dùng lệnh dưới. Surefire ghi báo cáo trong target/surefire-reports; khi lỗi, tìm test đầu tiên thất bại và so sánh expected với actual trước khi sửa code. Không xóa assertion để làm màu xanh nếu chưa giải thích được thay đổi hành vi.

.\mvnw.cmd test
.\mvnw.cmd -Dtest=CourseServiceTest test

Các test dùng dữ liệu riêng, không kết nối DB production và không gọi Internet hay SMTP thật. Cảnh báo cơ chế gắn agent của Mockito có thể xuất hiện tùy JDK; cần phân biệt cảnh báo với test failure. Nếu thay đổi JDK hoặc Mockito, đọc hướng dẫn chính thức về cấu hình agent và tương thích thay vì thêm cờ JVM không rõ nguồn.

Lỗi thường gặp và lưu ý

  • Không dùng @SpringBootTest cho mọi unit test nếu bài toán chỉ cần tạo một Service.
  • Một mock test pass không chứng minh migration, quyền truy cập hay serialization đều đúng.

Ghi nhớ

Unit test nhanh và có ý nghĩa khi nó kiểm tra một hành vi cụ thể với đầu vào và kỳ vọng rõ ràng.

Tài liệu đối chiếu

  • Spring Testing
  • Mockito

← Bài 24 · Mục lục 12 chương · Bài 26 →

Bài viết liên quan:

Java và Spring Boot – MVC và REST API
Spring Boot bài 16: Upload và download tài liệu có giới hạn
Java và Spring Boot – MVC và REST API
Spring Boot bài 17: Spring Security: đăng nhập, mật khẩu và SecurityFilterChain
Java và Spring Boot – MVC và REST API
Spring Boot bài 18: Phân quyền teacher/student và bảo vệ endpoint
Java và Spring Boot – MVC và REST API
Spring Boot bài 19: CSRF, CORS và gọi API có session đúng cách
Java và Spring Boot – MVC và REST API
Spring Boot bài 20: REST Controller, JSON và DTO cho API danh sách
Java và Spring Boot – MVC và REST API
Spring Boot bài 21: REST CRUD: POST, PUT, DELETE và mã trạng thái
Java và Spring Boot – MVC và REST API
Spring Boot bài 22: Validation API, ProblemDetail và hợp đồng lỗi
Java và Spring Boot – MVC và REST API
Spring Boot bài 23: Gọi dịch vụ HTTP bằng RestClient và đặt timeout
Java và Spring Boot – MVC và REST API
Spring Boot bài 08: Fragment, layout và tài nguyên CSS trong Spring Boot
Java và Spring Boot – MVC và REST API
Spring Boot bài 24: Gửi email và lập lịch tác vụ trong Spring Boot
Java và Spring Boot – MVC và REST API
Spring Boot bài 09: Binding biểu mẫu tạo và sửa khóa học
Java và Spring Boot – MVC và REST API
Spring Boot bài 26: Integration test MVC, API, database và Security

Dịch vụ thiết kế Wesbite

NỘI DUNG MỚI CẬP NHẬT

Giáo trình Python: mục lục 12 chương, 24 bài từ cơ bản đến ứng dụng

Python bài 24: Lock, Queue và thiết kế worker an toàn

Python bài 23: Thread, start, join và concurrency

Python bài 22: Kết nối MySQL và CRUD có transaction

Python bài 21: Gọi HTTP API, xử lý JSON và tải dữ liệu

Giới thiệu

hocvietcode.com là website chia sẻ và cập nhật tin tức công nghệ, chia sẻ kiến thức, kỹ năng. Chúng tôi rất cảm ơn và mong muốn nhận được nhiều phản hồi để có thể phục vụ quý bạn đọc tốt hơn !

Liên hệ quảng cáo: [email protected]

Kết nối với HỌC VIẾT CODE

© hocvietcode.com - Tech888 Co .Ltd since 2019

Đăng nhập

Trở thành một phần của cộng đồng của chúng tôi!
Registration complete. Please check your email.
Đăng nhập bằng google
Đăng kýBạn quên mật khẩu?

Create an account

Welcome! Register for an account
The user name or email address is not correct.
Registration confirmation will be emailed to you.
Log in Lost your password?

Reset password

Recover your password
Password reset email has been sent.
The email could not be sent. Possible reason: your host may have disabled the mail function.
A password will be e-mailed to you.
Log in Register
×