Bảo vệ mã của bạn bằng các bài kiểm tra đơn vị¶
Quan trọng
This tutorial is an extension of the Server framework 101 tutorial. Make sure you have
completed it and use the estate
module you have built as a base for the exercises in this
tutorial.
Tham khảo: Khung thử nghiệm của SoOn: Tìm hiểu các phương pháp thực hành tốt nhất (SoOn Experience 2020) trên YouTube.
Viết bài kiểm tra là một điều cần thiết vì nhiều lý do. Đây là một danh sách không đầy đủ:
Đảm bảo mã sẽ không bị hỏng trong tương lai
Xác định phạm vi mã của bạn
Cho ví dụ về các trường hợp sử dụng
Đó là một cách để ghi lại mã về mặt kỹ thuật
Giúp bạn viết mã bằng cách xác định mục tiêu trước khi thực hiện nó
Chạy thử nghiệm¶
Trước khi biết cách viết bài kiểm thử, chúng ta cần biết cách chạy chúng.
$ odoo-bin -h
Usage: odoo-bin [options]
Options:
--version show program's version number and exit
-h, --help show this help message and exit
[...]
Testing Configuration:
--test-file=TEST_FILE
Launch a python test file.
--test-enable Enable unit tests.
--test-tags=TEST_TAGS
Comma-separated list of specs to filter which tests to
execute. Enable unit tests if set. A filter spec has
the format: [-][tag][/module][:class][.method] The '-'
specifies if we want to include or exclude tests
matching this spec. The tag will match tags added on a
class with a @tagged decorator (all Test classes have
'standard' and 'at_install' tags until explicitly
removed, see the decorator documentation). '*' will
match all tags. If tag is omitted on include mode, its
value is 'standard'. If tag is omitted on exclude
mode, its value is '*'. The module, class, and method
will respectively match the module name, test class
name and test method name. Example: --test-tags
:TestClass.test_func,/test_module,external Filtering
and executing the tests happens twice: right after
each module installation/update and at the end of the
modules loading. At each stage tests are filtered by
--test-tags specs and additionally by dynamic specs
'at_install' and 'post_install' correspondingly.
--screencasts=DIR Screencasts will go in DIR/{db_name}/screencasts.
--screenshots=DIR Screenshots will go in DIR/{db_name}/screenshots.
Defaults to /tmp/odoo_tests.
$ # run all the tests of account, and modules installed by account
$ # the dependencies already installed are not tested
$ # this takes some time because you need to install the modules, but at_install
$ # and post_install are respected
$ odoo-bin -i account --test-enable
$ # run all the tests in this file
$ odoo-bin --test-file=addons/account/tests/test_account_move_entry.py
$ # test tags can help you filter quite easily
$ odoo-bin --test-tags=/account:TestAccountMove.test_custom_currency_on_account_1
Bot tích hợp¶
Ghi chú
Phần này chỉ dành cho nhân viên SoOn và những người đang đóng góp cho github.com/odoo
. Nếu không, chúng tôi thực sự khuyên bạn nên có CI của riêng mình.
Khi một bài kiểm thử được viết, điều quan trọng là phải đảm bảo rằng nó luôn đạt khi sửa đổi được áp dụng cho mã nguồn. Để tự động hóa tác vụ này, chúng tôi sử dụng phương pháp phát triển có tên là Tích hợp liên tục (CI). Đây là lý do tại sao chúng tôi có một số bot chạy tất cả các bài kiểm tra vào những thời điểm khác nhau. Cho dù bạn có đang làm việc tại SoOn hay không, nếu bạn đang cố gắng hợp nhất thứ gì đó bên trong odoo/odoo
, odoo/enterprise
, odoo/upgrade
hoặc trên odoo.sh, bạn sẽ phải thông qua CI. Nếu bạn đang làm việc trên một dự án khác, bạn nên nghĩ đến việc thêm CI của riêng mình.
Runbot¶
Tham khảo: tài liệu liên quan đến chủ đề này có thể được tìm thấy trong Câu hỏi thường gặp về Runbot.
Hầu hết các thử nghiệm đều được chạy trên Runbot mỗi khi một cam kết được đẩy lên GitHub.
Bạn có thể xem trạng thái của một cam kết/nhánh bằng cách lọc trên bảng điều khiển runbot.
gói được tạo cho mỗi nhánh. Một gói bao gồm một cấu hình và các lô.
batch là một tập hợp các bản dựng, tùy thuộc vào thông số của gói. Lô có màu xanh lục (tức là vượt qua các bài kiểm tra) nếu tất cả các bản dựng đều có màu xanh lục.
bản dựng là khi chúng tôi khởi chạy một máy chủ. Nó có thể được chia thành các bản dựng phụ. Thông thường có các bản dựng cho phiên bản cộng đồng, phiên bản doanh nghiệp (chỉ khi có chi nhánh doanh nghiệp nhưng bạn có thể buộc bản dựng) và quá trình di chuyển chi nhánh. Công trình có màu xanh nếu mọi công trình phụ đều có màu xanh.
bản dựng phụ chỉ thực hiện một số phần của bản dựng đầy đủ. Nó được sử dụng để tăng tốc quá trình CI. Nói chung, nó được sử dụng để chia các bài kiểm tra sau cài đặt thành 4 trường hợp song song. Bản dựng phụ có màu xanh lục nếu tất cả các thử nghiệm đều vượt qua và không có lỗi/cảnh báo nào được ghi lại.
Ghi chú
Tất cả các thử nghiệm đều được chạy bất kể sửa đổi được thực hiện. Sửa lỗi đánh máy trong thông báo lỗi hoặc tái cấu trúc toàn bộ mô-đun sẽ kích hoạt các thử nghiệm tương tự. Tất cả các mô-đun cũng sẽ được cài đặt. Điều này có nghĩa là một cái gì đó có thể không hoạt động ngay cả khi Runbot có màu xanh lá cây, tức là các thay đổi của bạn phụ thuộc vào mô-đun mà mô-đun chứa các thay đổi đó không phụ thuộc vào.
Các mô-đun bản địa hóa (tức là các mô-đun dành riêng cho từng quốc gia) không được cài đặt trên Runbot (ngoại trừ mô-đun chung). Một số mô-đun có phụ thuộc bên ngoài cũng có thể bị loại trừ.
Có một bản dựng hàng đêm chạy các thử nghiệm bổ sung: vận hành mô-đun, bản địa hóa, cài đặt mô-đun đơn, nhiều bản dựng cho các lỗi không xác định, v.v. Những bản dựng này không được lưu giữ trong CI tiêu chuẩn để rút ngắn thời gian thực thi.
Bạn cũng có thể đăng nhập vào bản dựng được xây dựng bởi Runbot. Có 3 người dùng có thể sử dụng được: admin
, demo
và portal
. Mật khẩu giống như thông tin đăng nhập. Điều này rất hữu ích để nhanh chóng kiểm tra mọi thứ trên các phiên bản khác nhau mà không cần phải xây dựng cục bộ. Nhật ký đầy đủ cũng có sẵn; chúng được sử dụng để theo dõi.
robotoo¶
Rất có thể bạn sẽ phải tích lũy thêm một chút kinh nghiệm trước khi có quyền triệu hồi robodoo, nhưng dù sao thì đây cũng là một vài nhận xét.
Robodoo là người gửi spam trạng thái CI dưới dạng thẻ trên PR của bạn, nhưng anh ấy cũng là người vui lòng tích hợp các cam kết của bạn vào kho lưu trữ chính.
Khi đợt cuối cùng có màu xanh lục, người đánh giá có thể yêu cầu robodoo hợp nhất PR của bạn (nó giống rebase
hơn là merge
). Sau đó nó sẽ đi đến mergebot.
Hợp nhất bot¶
Mergebot là giai đoạn thử nghiệm cuối cùng trước khi hợp nhất một PR.
Nó sẽ thực hiện các cam kết trong nhánh của bạn chưa có trên mục tiêu, thực hiện và chạy lại thử nghiệm một lần nữa, bao gồm cả phiên bản doanh nghiệp ngay cả khi bạn chỉ thay đổi điều gì đó trong cộng đồng.
Bước này có thể thất bại với thông báo lỗi Gia công không thành công
. Điều này có thể là do
một lỗi không xác định đã có trên mục tiêu. Nếu bạn là nhân viên SoOn, bạn có thể kiểm tra những thông tin đó tại đây: https://runbot.odoo.com/runbot/errors
một lỗi không xác định mà bạn đã đưa vào nhưng trước đó chưa được phát hiện trong CI
sự không tương thích với một cam kết khác đã được hợp nhất ngay trước đó và những gì bạn đang cố gắng hợp nhất
sự không tương thích với kho lưu trữ doanh nghiệp nếu bạn chỉ thực hiện các thay đổi trong kho lưu trữ cộng đồng
Luôn kiểm tra xem sự cố có phải do bạn gây ra hay không trước khi yêu cầu bot hợp nhất thử lại: khởi động lại nhánh của bạn theo mục tiêu và chạy lại thử nghiệm cục bộ.
Mô-đun¶
Vì SoOn có tính mô-đun nên các thử nghiệm cũng cần phải mang tính mô-đun. Điều này có nghĩa là các thử nghiệm được xác định trong mô-đun bổ sung chức năng mà bạn đang thêm vào và các thử nghiệm không thể phụ thuộc vào chức năng đến từ các mô-đun mà mô-đun của bạn không phụ thuộc vào.
Tham khảo: tài liệu liên quan đến chủ đề này có thể được tìm thấy trong Thẻ đặc biệt.
from odoo.tests.common import TransactionCase
from odoo.tests import tagged
# The CI will run these tests after all the modules are installed,
# not right after installing the one defining it.
@tagged('post_install', '-at_install') # add `post_install` and remove `at_install`
class PostInstallTestCase(TransactionCase):
def test_01(self):
...
@tagged('at_install') # this is the default
class AtInstallTestCase(TransactionCase):
def test_01(self):
...
Nếu hành vi bạn muốn kiểm tra có thể bị thay đổi khi cài đặt một mô-đun khác, bạn cần đảm bảo rằng thẻ at_install
đã được đặt; nếu không, bạn có thể sử dụng thẻ post_install
để tăng tốc CI và đảm bảo nó không bị thay đổi nếu không nên.
Viết bài kiểm tra¶
Tham khảo: tài liệu liên quan đến chủ đề này có thể được tìm thấy trong Python unittest và Testing SoOn.
Dưới đây là một số điều cần cân nhắc trước khi viết bài kiểm tra
Các thử nghiệm phải độc lập với dữ liệu hiện có trong cơ sở dữ liệu (bao gồm cả dữ liệu demo)
Các thử nghiệm không được tác động đến cơ sở dữ liệu bằng cách để lại/thay đổi dữ liệu còn lại. Điều này thường được khung kiểm tra thực hiện bằng cách thực hiện khôi phục. Do đó, bạn không bao giờ được gọi
cr.commit
trong bài kiểm tra (cũng như bất kỳ nơi nào khác trong mã doanh nghiệp).Để sửa lỗi, quá trình kiểm tra phải thất bại trước khi áp dụng bản sửa lỗi và vượt qua sau đó.
Đừng kiểm tra thứ gì đó đã được thử nghiệm ở nơi khác; bạn có thể tin tưởng vào ORM. Hầu hết các thử nghiệm trong mô-đun kinh doanh chỉ nên kiểm tra quy trình kinh doanh.
Bạn không cần phải xóa dữ liệu vào cơ sở dữ liệu.
Ghi chú
Hãy nhớ rằng onchange
chỉ áp dụng trong chế độ xem Biểu mẫu chứ không áp dụng bằng cách thay đổi các thuộc tính trong python. Điều này cũng được áp dụng trong các bài kiểm tra. Nếu bạn muốn mô phỏng chế độ xem Biểu mẫu, bạn có thể sử dụng odoo.tests.common.Form
.
Các bài kiểm tra phải nằm trong thư mục tests
ở thư mục gốc của mô-đun của bạn. Mỗi tên tệp kiểm tra phải bắt đầu bằng test_
và được nhập vào __init__.py
của thư mục kiểm tra. Bạn không nên nhập thư mục/mô-đun kiểm tra vào __init__.py
của mô-đun.
estate
├── models
│ ├── *.py
│ └── __init__.py
├── tests
│ ├── test_*.py
│ └── __init__.py
├── __init__.py
└── __manifest__.py
Tất cả các thử nghiệm phải mở rộng odoo.tests.common.TransactionCase
. Bạn thường định nghĩa một setUpClass
và các bài kiểm tra. Sau khi viết setUpClass
, bạn có sẵn env
trong lớp và có thể bắt đầu tương tác với ORM.
Các lớp kiểm tra này được xây dựng dựa trên mô-đun python unittest
.
from odoo.tests.common import TransactionCase
from odoo.exceptions import UserError
from odoo.tests import tagged
# The CI will run these tests after all the modules are installed,
# not right after installing the one defining it.
@tagged('post_install', '-at_install')
class EstateTestCase(TransactionCase):
@classmethod
def setUpClass(cls):
# add env on cls and many other things
super(EstateTestCase, cls).setUpClass()
# create the data for each tests. By doing it in the setUpClass instead
# of in a setUp or in each test case, we reduce the testing time and
# the duplication of code.
cls.properties = cls.env['estate.property'].create([...])
def test_creation_area(self):
"""Test that the total_area is computed like it should."""
self.properties.living_area = 20
self.assertRecordValues(self.properties, [
{'name': ..., 'total_area': ...},
{'name': ..., 'total_area': ...},
])
def test_action_sell(self):
"""Test that everything behaves like it should when selling a property."""
self.properties.action_sold()
self.assertRecordValues(self.properties, [
{'name': ..., 'state': ...},
{'name': ..., 'state': ...},
])
with self.assertRaises(UserError):
self.properties.forbidden_action_on_sold_property()
Ghi chú
Để dễ đọc hơn, hãy chia bài kiểm tra của bạn thành nhiều tệp tùy thuộc vào phạm vi kiểm tra. Bạn cũng có thể có một lớp Common mà hầu hết các bài kiểm tra sẽ kế thừa từ đó; lớp chung này có thể xác định toàn bộ thiết lập cho mô-đun. Ví dụ: trong tài khoản.
Exercise
Cập nhật mã để không ai có thể:
Tạo một đề nghị cho một tài sản đã bán
Bán một tài sản không có lời đề nghị nào được chấp nhận
và tạo các bài kiểm tra cho cả hai trường hợp này. Ngoài ra, hãy kiểm tra xem việc bán bất động sản có thể bán được có được đánh dấu chính xác là đã bán sau khi bán hay không.
Exercise
Ai đó liên tục vi phạm việc đặt lại Khu vườn và Hướng khi bạn bỏ chọn hộp kiểm Khu vườn. Hãy chắc chắn rằng nó không xảy ra lần nữa.
Mẹo
Mẹo: hãy nhớ lưu ý về Form
ở trên một chút nhé.