Ở bài trước mình đã dán hai nhãn @tagged('post_install', '-at_install') lên lớp test mà chưa giải thích. Chúng không phải trang trí — chúng quyết định thời điểm test chạy trong quá trình cài Odoo, và chọn sai là nguồn của một loại bug khó chịu: test lúc xanh lúc đỏ mà không rõ vì sao. Bài này mổ xẻ @tagged, hai nhãn at_install/post_install, và chứng minh sự khác biệt bằng log thật.

Hai thời điểm chạy test

Khi Odoo cài/nâng cấp, nó nạp lần lượt hàng trăm module. Test của module bạn có thể chạy ở hai thời điểm:

  • at_install (mặc định): chạy ngay sau khi module của bạn được cài, trước khi các module còn lại cài xong. Môi trường lúc này "tinh khiết" — chỉ có module bạn và những gì nó phụ thuộc.
  • post_install: chạy sau khi TẤT CẢ module đã cài xong. Môi trường "đầy đủ", giống hệt production.

Khai bằng decorator @tagged:

Ảnh chụp mã Python nền tối file test_tags.py ba lớp. Import TransactionCase và tagged. Lớp TestChayLucCai không khai tag nên mặc định at_install, method test_moc_at_install dùng assertIn quan the thanh vien trong self env registry. Lớp TestChaySauCai có decorator tagged post_install và trừ at_install nghĩa bật post tắt at bằng dấu trừ, method test_moc_post_install lấy search_count rồi assertGreaterEqual 0. Lớp TestCoTagRieng có decorator tagged post_install trừ at_install và thêm tag tuỳ biến chi_toi để lọc riêng bằng test-tags chi_toi, method test_moc_tag_rieng assertEqual 1 cộng 1 bằng 2

Hình 1: Ba lớp test với ba cấu hình tag. TestChayLucCai không khai gì → mặc định at_install. TestChaySauCai khai @tagged('post_install', '-at_install') — bật post_install, và dấu trừ -at_install tắt nhãn mặc định (nếu không, nó chạy cả hai lần). TestCoTagRieng thêm một tag tuỳ biến 'chi_toi' để lọc riêng sau này.

Chứng minh bằng log thật

Đây là phần thú vị. Mình chạy cả ba test trên blog19 và đọc kỹ thứ tự trong log — nó phơi bày đúng cơ chế:

Ảnh chụp terminal nền tối hai phần chạy test thật. Phần 1 chạy đủ với test-tags gạch chéo quan_ca_phe. Log loading 175 modules, dòng Loading module quan_ca_phe 94 trên 175 tô cam, ngay sau đó MOC at_install chạy ngay sau khi cài quan_ca_phe chú thích mới 94 trên 175, rồi dòng 175 modules loaded in 0.79s tô cam chú thích cài xong tất cả, tiếp theo Starting TestChaySauCai và MOC post_install chạy sau khi cài hết mọi module, cuối cùng result 0 failed 0 errors of 3 tests màu xanh. Phần 2 lọc theo tag tuỳ biến chi_toi chỉ Starting TestCoTagRieng và MOC tag_rieng rồi result 0 failed 0 errors of 1 tests chú thích hai lớp kia bị bỏ qua

Hình 2: Thật, và rất rõ. Ở phần 1: test at_install chạy ngay sau "Loading module quan_ca_phe (94/175)" — mới cài 94 trên 175 module! Còn test post_install chạy sau dòng "175 modules loaded" — khi mọi module đã xong. Hai test chạy ở hai thời điểm hoàn toàn khác nhau của tiến trình cài. Phần 2: lọc --test-tags=chi_toi → chỉ 1 test chạy, hai lớp kia bị bỏ qua.

Vì sao chọn sai gây "test đỏ ngẫu nhiên"

Giờ hiểu tại sao nhãn này quan trọng. Giả sử test của bạn kiểm một tính năng đụng tới module khác — ví dụ tạo một đơn bán hàng (sale), hay gọi một route của website. Nếu để test đó chạy ở at_install, mà module sale/website được cài SAU module của bạn, thì lúc test chạy chúng chưa tồn tại → test đỏ. Nhưng nếu cài theo thứ tự khác, chúng có thể đã sẵn → test xanh. Kết quả: test đỏ hay xanh phụ thuộc thứ tự cài, không phụ thuộc code — cực khó lần.

Quy tắc đơn giản:

  • Test chỉ đụng model của chính module bạn → để at_install (mặc định), chạy sớm, nhanh.
  • Test đụng tính năng/dữ liệu của module khác, hay cần môi trường giống production → dùng post_install.

Khi phân vân, post_install là lựa chọn an toàn hơn — đó là lý do phần lớn test thực tế đều mang nhãn này.

Lọc test bằng --test-tags

Cú pháp --test-tags rất linh hoạt, ghép nhiều điều kiện bằng dấu phẩy:

--test-tags=/quan_ca_phe      # mọi test của module quan_ca_phe
--test-tags=chi_toi           # mọi test mang tag tuỳ biến 'chi_toi'
--test-tags=-slow             # loại test có tag 'slow'
--test-tags=.TestChaySauCai   # chỉ một lớp
--test-tags=:test_moc_tag_rieng  # chỉ một method

Các tiền tố: / = module, . = lớp, : = method, - = loại trừ, không tiền tố = tên tag. Mặc định mọi test mang nhãn ngầm standard; --test-tags cho bạn chạy đúng nhóm cần trong lúc phát triển thay vì chờ toàn bộ.

Ba ý mang về

  1. @tagged quyết định KHI NÀO test chạy: at_install (mặc định) chạy ngay sau khi cài module bạn — đã thấy nó chạy lúc mới 94/175 module; post_install chạy sau khi tất cả module cài xong (sau dòng "175 modules loaded").
  2. @tagged('post_install', '-at_install') bật post_install và dấu trừ tắt nhãn mặc định. Test đụng module khác mà để at_install sẽ đỏ ngẫu nhiên theo thứ tự cài — dùng post_install cho an toàn.
  3. --test-tags lọc test theo module (/), lớp (.), method (:), tag tuỳ biến, và loại trừ (-) — đã chứng minh --test-tags=chi_toi chỉ chạy đúng 1 lớp.

Đã biết viết test và điều khiển khi nào chúng chạy, phần còn thiếu là viết test cho tốt. Phần sau bàn về dựng dữ liệu và assert đúng cách — cách tạo dữ liệu nền gọn gàng, chọn đúng phép assert, và những cạm bẫy khiến test "xanh giả" mà không thực sự kiểm được gì.