Automated Test Cases

Khi phát triển một module lớn và phức tạp, việc sử dụng các kịch bản kiểm thử tự động là một phương pháp tốt cải thiện độ tin cậy cho module. Việc này làm module của bạn trở nên tốt hơn. Hàng năm, Odoo phát hành ra các phiên bản mới, các kịch bản kiểm thử tự động giúp phát hiện các vấn đề đang xảy ra với module trong quá trình nâng cấp. Thật may, với bất kỳ các phiên bản Odoo cũng đi kèm các tiện ích kịch bản kiểm thử tự động khác nhau. Odoo cung cấp 3 loại kịch bản kiểm thử chính:

  • Kịch bản kịch bản kiểm thử Python: Được sử dụng để kịch bản kiểm thử logic nghiệp vụ Python.

  • Kịch bản kịch bản kiểm thử JavaScript QUnit: Được sử dụng để kịch bản kiểm thử việc triển khai JavaScript trong Odoo

  • Tours: Kiểm thử tích hợp để đảm bảo Python và Javascript hoạt động bình thường với nhau.

Trong phần này, chúng ta sẽ đi vào các đầu mục:

Yêu cầu kỹ thuật

Trong phần này, chúng ta sẽ xem xét tất cả các kịch bản kiểm thử một cách chi tiết. Để xem xét tất cả các kịch bản kiểm thử trong cùng một module, chúng ta sẽ tạo một module nhỏ với đoạn code python dưới đây:

from odoo import fields, models


class EducationStudent(models.Model):
    _name = 'education.student'
    _inherit = ['mail.thread', 'mail.activity.mixin']
    _inherits = {'res.partner': 'partner_id'}
    _description = 'Education Student'

    partner_id = fields.Many2one('res.partner', string='Student', ondelete="restrict", required=True)
    state = fields.Selection(string='Status', selection=[('new', 'New'),
                                                         ('studying', 'Studying'),
                                                         ('off', 'Off')], default='new', tracking=True)

    def action_start(self):
        self.write({'state': 'studying'})

    def action_close(self):
        self.write({'state': 'off'})

Thêm các kịch bản kiểm thử Python

Các kịch bản kiểm thử dưới đây để kiểm tra sự chính xác của các tính năng có trong module:

  • Thay đổi hồ sơ học sinh từ trạng thái Mới sang Đang học.

  • Thay đổi hồ sơ học sinh từ trạng thái Đang học sang Đã nghỉ.

Các bước thực hiện

Dưới đây là các bước để thêm một kịch bản kiểm thử tự động vào module.

  1. Thêm một file mới, tests/__init__.py như sau:

    from . import test_student_state
    
  2. Thêm một file tests/test_student_state.py, và bổ sung các kịch bản kiểm thử như dưới đây:

    from odoo.tests.common import TransactionCase
    
    
    class TestStudentState(TransactionCase):
    
        def setUp(self, *args, **kwargs):
            super(TestStudentState, self).setUp(*args, **kwargs)
            self.test_student = self.env['education.student'].create({'name': 'Luis Tran'})
    
        def test_action_start(self):
            """
            Make start button
            """
            self.test_student.action_start()
            self.assertEqual(self.test_student.state, 'studying', "Student state should be chagned to studying")
    
        def test_action_close(self):
            """
              Make close button
            """
            self.test_student.action_close()
            self.assertEqual(self.test_student.state, 'off', "Student state should be chagned to off")
    
  3. Để chạy các kịch bản kiểm thử, chúng ta sẽ khởi động lại server với tùy chọn sau:

    ./odoo-bin -c ~/project.conf -i viin_education --test-enable
    

Kiểm tra server log. Bạn sẽ tìm thấy các dòng log nếu các kịch bản kiểm thử của chúng ta thành công:

Bạn sẽ thấy log ERROR thay vì INFO nếu trong trong các kịch bản kiểm thử của chúng ta bị lỗi.

Cơ chế hoạt động

Trong Odoo, Khi thêm các kịch bản kiểm thử Python vào thư mục tests of module. Odoo sẽ tự động xác định thư mục này và chạy các kịch bản kiểm thử bên trong.

Note

Bạn cũng cần khai báo 1 danh sách file chứa các kịch bản kiểm thử của bạn trong tests/__init__.py. Nếu không khai báo thì các kịch bản kiểm thử đó sẽ không được tiến hành.

Odoo hiện đang sử dụng Unittest của Python cho các kịch bản kiểm thử. Bạn cũng có thể tìm hiểu thêm về Unittest của Python tại https://docs.python.org/3/library/unittest.html. Odoo cung cấp một số class hỗ trợ cải tiến các unittest, giúp đơn giản hóa quá trình phát triển các kịch bản kiểm thử. Trong các kịch bản kiểm thử được giới thiệu ở trên đang sử dụng TransactionCase. TransactionCase sẽ chạy các phương thức kịch bản kiểm thử trong các phiên khác nhau. Khi một phương thức kịch bản kiểm thử chạy thành công, phiên sẽ tự động khôi phục lại dữ liệu liệu như ban đầu. Điều này có nghĩa là kịch bản kiểm thử tiếp theo sẽ không bị ảnh hưởng bởi các thay đổi từ kịch bản kiểm thử trước đó.

Các phương thức kịch bản kiểm thử thường bắt đầu bằng test_ và được coi là một kịch bản kiểm thử. Trong ví dụ ở trên, chúng ta đã thêm 2 kịch bản kiểm thử để kiểm tra sự thay đổi trạng thái của học sinh. Phương thức self.assertEqual để kiểm tra các kịch bản kiểm thử có chạy đúng như mong đợi hay không. Do vậy, nếu tính năng phát triển bị lỗi và phương thức không thay đổi được trạng thái như mong đợi, kịch bản kiểm thử này sẽ thất bại.

Một số thông tin quan trọng

Lưu ý rằng phương thức setUp() sẽ tự động gọi bởi tất cả các kịch bản kiểm thử mà chúng ta chạy, bởi vậy trong mục này chúng ta bổ sung hai kịch bản kiểm thử nên do đó phương thức setUp() sẽ gọi 2 lần. Mỗi đoạn code trong mục này sẽ chỉ sử dụng một bản ghi học sinh trong quá trình kịch bản kiểm thử, bởi vì đây là TransactionCase nên các phiên sẽ được khôi phục lại sau mỗi kịch bản kiểm thử.

Docstrings trên phương thức sẽ được in trong log. Nó sẽ rất hữu ích cho việc kiểm tra trạng thái của một kịch bản kiểm thử cụ thể.

Ngoài ra, bộ kịch bản kiểm thử cung cấp thêm các class kịch bản kiểm thử tiện ích khác:

  • SingleTransactionCase: Các kịch bản kiểm thử được tạo thông qua class này sẽ được chạy toàn bộ thông qua một phiên duy nhất, vì vậy sự thay đổi trong kịch bản kiểm thử đầu sẽ có ở trong kịch bản kiểm thử tiếp theo. Phiên được bắt đầu ở kịch bản đầu tiên và sẽ chỉ đóng sau khi chạy xong kịch bản cuối cùng.

  • SavepointCase: Cũng giống như SingleTransactionCase, nhưng các phương thức kịch bản kiểm thử được chạy bên trong một rolled-back savepoint, thay vì chạy tất cả các phương thức kịch bản kiểm thử trong một phiên duy nhất. Nó được dùng để tạo ra các kịch bản kiểm thử lớn và phức tạp, giúp chúng chạy nhanh hơn bằng cách chỉ tạo dữ liệu ban đầu một lần. Trong class này chúng ta sử dụng phương thức setUpClass() để khởi tạo dữ liệu ban đầu.

Chạy các kịch bản kiểm thử Python được gắn thể

Khi chạy Odoo server với tham số --test-enable, các kịch bản kiểm thử chạy ngay sau khi module được cài đặt. Nếu bạn muốn chạy kịch bản kiểm thử sau khi cài đặt tất cả các module, hoặc bạn chỉ muốn chạy một kịch bản kiểm thử cho một module nào đó, bạn cần sử dụng decorator tagged(). Trong phần này, chúng ta sẽ tìm hiểu làm thế nào để sử dụng tagged() trong kịch bản kiểm thử.

Chuẩn bị

Trong phần này chúng ta sẽ sử dụng module viin_education, thực hành các kịch bản kiểm thử sử dụng tagged().

Các bước thực hiện:

  1. Thêm decorator tagged() vào class kịch bản kiểm thử để nó chạy sau khi cài hết tất cả các module.

    from odoo.tests.common import TransactionCase, tagged
    
    @tagged('-at_install', 'post_install')
    class TestStudentState(TransactionCase):
    
  2. Sau đó chạy lại các kịch bản kiểm thử:

    ./odoo-bin -c ~/server.conf -i viin_education --test-enable
    
  3. Kiểm tra log server bạn sẽ thấy log của các kịch bản kiểm thử sau các log, nghĩa là các test của chúng ta sẽ chạy sau khi cái tất cả các module, như dưới đây:

    ... INFO student odoo.modules.loading: 9 modules loaded in 1.87s, 177 queries (+0 extra)
    ... INFO student odoo.modules.loading: Modules loaded.
    ... INFO student odoo.service.server: Starting post tests
    ... INFO student odoo.addons.viin_education.tests.test_education_student: Starting TestStudentState.test_button_start ...
    ... INFO student odoo.addons.viin_education.tests.test_education_student: Starting TestBookState.test_action_close ...
    ... INFO student odoo.service.server: 2 post-tests in 0.14s,
    10 queries
    

Dòng đầu tiên cho thấy 9 module đã được nạp. Dòng thứ 2 cho thấy tất cả các module được yêu cầu và phụ thuộc nó được cài đặt thành công, dòng thứ 3 bắt đầu chạy kịch bản kiểm thử với các kịch bản kiểm thử được gắn taggedpost_install.

Cơ chế hoạt động

Mặc định, tất cả các kịch bản kiểm thử được gắn các thẻ standard, at_install và tên kỹ thuật của module hiện tại, trong ví dụ này tên kỹ thuật của module là viin_education. Do đó, nếu bạn không sử dụng decorator tagged(), các kịch bản kiểm thử của bạn sẽ có mặc định 3 thẻ.

Ở ví dụ này, chúng ta muốn các kịch bản kiểm thử chạy sau khi cài đặt tất cả các module. Chúng ta thêm decorator tagged() cho class TestStudentState. Mặc định, các kịch bản kiểm thử đều được gắn thẻ at_install. Bởi vì thẻ này nên các kịch bản kiểm thử của bạn sẽ chạy ngay khi cài đặt module xong mà không chờ tất cả các module khác được cài. Chúng ta không mong muốn điều đó, vì vậy để xóa thẻ at_install, chúng ta thêm -at_install vào hàm tagged(). Các thẻ với tiền tố - sẽ xóa bỏ thẻ đó.

Thêm -at_install vào hàm tagged(), chúng ta sẽ bỏ qua việc chạy các kịch bản kiểm thử sau khi cài đặt module. Vì chúng ta chưa chỉ định các thẻ khác, nên các kịch bản kiểm thử này sẽ không chạy.

Do đó, chúng ta cần thêm tag post_install. Thẻ này chỉ định rằng các kịch bản kiểm thử cần được chạy sau khi tất cả các module đã được cài đặt.

Như bạn đã thấy, mặc định tất cả các kịch bản kiểm thử đều được gắn thẻ standard. Odoo sẽ chạy tất cả các kịch bản kiểm thử gắn thẻ standard. Trong trường hợp bạn muốn một kịch bản kiểm thử nảo đó chỉ được chạy khi có yêu cầu, bạn cần xóa thẻ standard bằng các thêm -standard vào trong hàm tagged(), và bạn cũng có thể thêm 1 thẻ tuỳ chỉnh khác:

@tagged('-standard', 'custom_tag')
class TestEducation(TransactionCase):
...

Tất cả kịch bản không gắn thẻ standard sẽ không chạy với tùy chọn --test-enable. Bạn cần sử dụng tùy chọn --test-tags, như trong ví dụ dưới đây (không cần sử dụng tùy chọn --test-enable):

./odoo-bin -c ~/project.conf -i viin_education --test-tags=custom_tag

Trong phát triển các kịch bản kiểm thử, việc chạy các kịch bản kiểm thử trong một module là quan trọng. Mặc định tên kỹ thuật của module được coi là một thẻ, do vậy bạn có thể sử dụng tùy chọn --test-tags với tên module. Ví dụ bạn muốn chạy các kiểm tử cho module viin_education, bạn có thể chạy dòng lệnh dưới đây:

./odoo-bin -c project.conf -i viin_education --test-tags=viin_education

Odoo sử dụng Headless Chrome tiến hành các kịch bản kiểm thử JavaScript và kịch bản kiểm thử theo tour. Headless Chrome là một cách chạy Chrome không có đầy đủ giao diện. Bằng cách này, chúng ta có thể chạy các kịch bản kiểm thử JavaScript trong môi trường giống với môi trường của người dùng. Trong phần này, chúng ta sẽ sử dụng Headless Chrome và các gói khác để chạy các kịch bản kiểm thử JavaScript.

Thiết lập Headless Chrome cho phía client kịch bản kiểm thử

Odoo sử dụng Headless Chrome tiến hành các kịch bản kiểm thử JavaScript và kịch bản kiểm thử theo tour. Headless Chrome là một cách chạy Chrome không có đầy đủ giao diện. Bằng cách này, chúng ta có thể chạy các kịch bản kiểm thử JavaScript trong môi trường giống với môi trường của người dùng. Trong phần này, chúng ta sẽ sử dụng Headless Chrome và các gói khác để chạy các kịch bản kiểm thử JavaScript.

Các bước thực hiện

Bạn sẽ cần cài đặt Chrome để kích hoạt các kịch bản kiểm thử JavaScript. Để phát triển module, chúng ta thường sử dụng desktop OS. Do đó, nếu bạn đã cài đặt trình duyệt Chrome trên hệ thống của mình thì không cần phải cài đặt riêng. Bạn có thể chạy các kịch bản kiểm thử phía client với Desktop Chrome. Đảm bảo phiên bản Chrome cao hơn Chrome 59. Odoo cũng hỗ trợ trình duyệt Chromium.

Note

Các kịch bản kiểm thử Headless Chrome phía client hoạt động tốt trên macOs và Linux, nhưng Odoo không hỗ trợ kịch bản kiểm thử Headless Chrome trên Windows.

Có chút khác biệt khi bạn chạy các kịch bản kiểm thử trên máy chủ chính thức hoặc trên Server OS. Server OS không có giao diện, do vậy bạn cần cài Chrome theo cách khác. Nếu bạn sử dụng OS dựa trên Debian, bạn có thể cài Chromium với dòng lệnh dưới đây:

apt-get install chromium-browser

Thông tin quan trọng

Ubuntu 18.04 Server Edition mặc định không kích hoạt kho universe. Do đó, có thể sẽ gặp lỗi khi cài đặt chromium-browser. Để khắc phục lỗi, hãy bật kho universe với dòng lệnh sau: sudo add-apt-repository universe.

Odoo cũng sử dụng WebSocket cho các kịch bản kiểm thử JavaScript. Do đó, Odoo sử dụng thư viện python websocket-client. Để cài đặt nó sử dụng lệnh sau:

pip3 install websocket-client

Giờ thì hệ thống của bạn đã sẵn sàng chạy các kịch bản kiểm thử phía client.

Cơ chế hoạt động

Odoo sử dụng Headless Chrome cho các kịch bản kiểm thử JavaScript. Lý do đằng sau điều này là nó chạy các kịch bản kiểm thử trong background, vì vậy nó có thể chạy trên Server OS. Headless Chrome cho phép chạy trình duyệt Chrome trong background mà không cần mở trình duyệt. Odoo mở một tab Chrome trong background và bắt đầu chạy các kịch bản kiểm thử trong nó. Nó cũng sử dụng jQuery’s QUnit cho các kịch bản kiểm thử JavaScript. Trong phần tiếp theo, chúng ta sẽ tạo một kịch bản kiểm thử QUnit cho JavaScript widget.

Đối với các kịch bản kiểm thử, Odoo mở Headless Chrome trong một tiến trình riêng biệt. Do đó, để xem trạng thái của một kịch bản kiểm thử chạy trong đó, server Odoo sử dụng WebSockets. Thư viện websocket-client của Python được sử dụng để quản lý các WebSocket để kết nối với Chrome từ server Odoo.

Thêm các kịch bản kiểm thử QUnit phía client

Xây dựng một field mới hoặc một view mới rất đơn giản trong Odoo. Chỉ với một vài dòng XML, bạn có để định nghĩa một view mới. Tuy nhiên, phía trong lại sử dụng rất nhiều JavaScript. Việc chỉnh sửa/thêm tính năng mới bên phía client rất phức tạp, có thể phá vỡ một vài thứ. Phần lớn các vấn đề xảy ra không thấy ở phía client, vì hầu hết các lỗi chỉ hiển thị trong console. Vì vậy, Các kịch bản kiểm thử QUnit được sử dụng trong Odoo để kịch bản kiểm thử tính đúng đắn của các thành phần JavaScript khác nhau.

Chuẩn bị

Trong phần này, chúng ta tiếp tục sử dụng module viin_education từ phần trước. Chúng ta sẽ thêm kịch bản kiểm thử QUnit cho widget float_range:

Các bước thực hiện

Dưới đây là các bước để thêm các kịch bản kiểm thử JavaScript cho widget float_range:

  1. Thêm /static/tests/float_range_tests.js:

    odoo.define('float_range_tests', function (require) {
    "use strict";
    
    var FormView = require('web.FormView');
    var testUtils = require('web.test_utils');
    
    var testUtilsDom = require('web.test_utils_dom');
    
    function clickCreate(kanban) {
      return testUtilsDom.click(kanban.$buttons.find('.o-kanban-button-new'));
    }
    
    QUnit.module('Float Range Tests', {
      beforeEach: function () {
          this.data = {
              student: {
                  fields: {
                      name: { string: "Name", type: "char" },
                      rating: { string: "Rating", type: "float"},
                  },
                  records: [{
                      id: 1,
                      name: "Student 1",
                      rating: 3.0
                  }, {
                      id: 2,
                      name: "Student 2",
                      rating: 5.0
                  }]
              }
          };
      }
      }, function () {
      // Place step 2 here
    });
    });
    
  2. Thêm một kịch bản kiểm thử cho trường float_range:

    QUnit.test('float_range field test cases', async function (assert) {
    assert.expect(2);
    var form = await testUtils.createView({
        View: FormView,
        model: 'student',
        data: this.data,
        arch: '<form string="Students">' +
            '<group>' +
                '<field name="name"/>' +
                '<field name="rating" widget="float_range" />' +
            '</group>' +
            '</form>',
        res_id: 1,
    });
    
    await testUtils.form.clickEdit(form);
    assert.strictEqual(form.$('.o_float_range_input').length, 1, "Should have input range");
    
    assert.strictEqual(form.$('.o_float_range_value')[0].outerText, '3', "The text must be 3");
    form.destroy();
    });
    
  3. Thêm đoạn code dưới đây vào /views/template.xml để đăng ký bộ kịch bản kiểm thử:

    ...
        <template id="qunit_suite" name="float_range test" inherit_id="web.qunit_suite">
         <xpath expr="." position="inside">
            <script type="text/javascript" src="/viin_education/static/tests/float_range_tests.js" />
         </xpath>
        </template>
    ...
    

Để chạy kịch bản kiểm thử này, chúng ta cần kích hoạt chế độ phát triển, click vào icon hình con bọ và chọn Chạy kiểm tra JS.

Chạy test Js

Kiểm tra các kịch bản kiểm thử đã chạy thành công như hình dưới đây:

Kết quả chạy test Js

Cơ chế hoạt động

Trong Odoo, các kịch bản kiểm thử JavaScript được thêm vào thư mục static/tests/. Trong bước 1, chúng ta viết các kịch bản kiểm thử vào trong file float_range_tests.js. Trong file đó, chúng ta import formViewtest_utils. web.FormView cần được import bởi vì chúng ta đã tạo widget float_range cho giao diện form, vì vậy khi kịch bản kiểm thử widget đó cần giao diện form. web.test_utils sẽ cung cấp cho chúng ta các tiện ích kịch bản kiểm thử cần thiết cho việc xây dựng kịch bản kiểm thử.

Các kịch bản kiểm thử phía client Odoo được xây dựng bằng framework QUnit, bản chất là framework jQuery cho các kịch bản kiểm thử JavaScript. Để tìm hiểu thêm hãy truy cập https://qunitjs.com/. Hàm beforeEach được gọi trước khi chạy các kịch bản kiểm thử và nó giúp khởi tạo các dữ liệu ban đầu. Hàm beforeEach được cung cấp bởi framework QUnit.

Chúng ta đã khởi tạo dữ liệu trong hàm beforeEach. Hãy xem dữ liệu đó đang được sử dụng như thế nào trong kịch bản kiểm thử. Kiểm thử phía client được chạy trong môi trường độc lập (mock) và nó không liên kết với cơ sở dữ liệu, vì vậy đối với các kịch bản kiểm thử này, chúng ta cần tạo dữ liệu ban đầu. Odoo khởi tạo server giả lập Remote Procedure Call (RPC) và sử dụng thuộc tính this.data làm cơ sở dữ liệu. Do đó, trong beforeEach, chúng khởi tạo dữ liệu kịch bản kiểm thử của mình trong thuộc tính this.data. Các khóa trong thuộc tính this.data là một bảng, và các giá trị chứa thông tin về các trường và các hàng trong bảng. Khóa fields được dùng để định nghĩa các trường trong bảng và khóa records được sử dụng cho các hàng của bảng. Trong ví dụ chúng ta đã thêm bảng student với 2 trường: name (Char)rating (float). Lưu ý răng bạn có thể sử dụng bất kỳ trường nào trong Odoo, kể cả các trường quan hệ, ví dụ {string: "M2oField", type: "many2one", relation: 'partner'}. Chúng cũng đã thêm 2 bản ghi học sinh với khóa records.

Tiếp theo, chúng ta thêm các kịch bản kiểm thử với hàm QUnit.test, Tham số đầu tiên trong hàm là string mô tả kịch bản kiểm thử. Tham số thứ 2 là hàm mà bạn sẽ viết code kịch bản kiểm thử. Hàm này được gọi từ framework QUnit và nó truyền vào tiện ích assert làm tham số. Trong ví dụ, chúng đã truyền vào số lượng các kịch bản kiểm thử dự kiến trong hàm assert.expect. Chúng ta sẽ thêm 2 kịch bản kiểm thử, vì vậy chúng ta truyền vào 2.

Chúng ta muốn thêm kịch bản kiểm thử widget float_range trên giao diện form ở trạng thái chỉnh sửa, vì vậy chúng đã tạo giao diện form với testUtils.createView. Hàm createView cho phép một số tham số khác nhau như sau:

  • View` là tham chiếu kiểu giao diện bạn muốn tạo, bạn có thể tạo bất kỳ kiểu giao diện nào cho kịch bản kiểm thử; bạn chỉ cần truyền vào kiểu giao diện tại đây.

  • model` là tên của model để tạo giao diện. Tất cả các model đều đã được khai báo trong thuộc tính this.data. Chúng ta muốn tạo một giao diện cho model student, vì vậy trong ví dụ đã sử dụng student như một model.

  • data là bản ghi sẽ được sử dụng trong giao diện.

  • arch là định nghĩa của giao diện bạn muốn tạo . Vì chúng ta muốn kịch bản kiểm thử widget float_range, chúng ta đã truyền vào định nghĩa giao diện có widget đó. Lưu ý là bạn chỉ sử dụng được các trường đã định nghĩa trong model.

  • res_idid bản ghi đang hiển thị. Tùy chọn này chỉ sử dụng trên giao diện form. Trong kịch bản kiểm thử , giao diện form sẽ hiển thị với dữ liệu của bản ghi Student 1, vì vậy chúng ta điền 1 vào res_id.

Sau khi tạo giao diện form với widget float_range, chúng ta thêm 2 kịch bản kiểm thử. Kiểm thử đầu tiên được sử dụng để kiểm tra số lượng trường float_range xuất hiện trên giao diện người dùng, kịch bản kiểm thử thứ 2 được sử dụng để kiểm tra giá trị hiển thị trên trường ‘rating` có chính xác hay không.

Chúng ta có hàm strictEqual từ các tiện ích của QUnit framework. Hàm strictEqual kịch bản kiểm thử thành công khi 2 tham số đầu tiên khớp nhau, nếu không khớp thì kịch bản kiểm thử sẽ thất bại.

Bạn có thể tìm hiểu thêm một vài hàm assert có sẵn trong các Qunit test tại https://qunitjs.com, như assert.deepEqual, assert.okassert.notOk.

Thêm kịch bản kiểm thử theo tour

Các phần trước bạn đã thấy các kịch bản kiểm thử Python và JavaScript. Cả hai đều hoạt động trong một môi trường riêng biệt và chúng không tương tác với nhau. Để kiểm tra tích hợp giữa JavaScript và Python, các kịch bản kiểm thử tour sẽ được sử dụng trong trường hợp này.

Chuẩn bị

Trong phần này, chúng ta sẽ tiếp tục sử dụng module viin_education từ phần trước. Chúng ta sẽ thêm các kịch bản kiểm thử để kiểm tra luồng nghiệp vụ của model education.student. Phải đảm bảo module web_tour đã được cài hoặc được thêm vào depends trong file manifest.

Các bước thực hiện

Dưới đây là các bước để thêm một kịch bản kiểm thử tour cho các học sinh:

  1. Thêm một file /static/src/js/viin_education_tour.js và bổ sung một tour như sau:

    odoo.define('education.tour', function (require) {
     "use strict";
    
     var core = require('web.core');
     var tour = require('web_tour.tour');
     var _t = core._t;
    
     tour.register('education_tour', {
         url: "/web",
         rainbowManMessage: _t("Congrats, you have create a student."),
         sequence: 5,
     }, [
         tour.stepUtils.showAppsMenuItem(),
         // Place step 3 here
     ]);
    });
    
  2. Thêm các bước cho kịch bản kiểm thử tour:

    odoo.define('education.tour', function (require) {
      "use strict";
    
      var core = require('web.core');
      var tour = require('web_tour.tour');
      var _t = core._t;
    
      tour.register('education_tour', {
          url: "/web",
          rainbowManMessage: _t("Congrats, you have create a student."),
          sequence: 5,
      }, [
          tour.stepUtils.showAppsMenuItem(), {
              trigger: '.o_app[data-menu-xmlid="viin_education.education_management_menu_root"]',
              content: _t('Manage students and classes in <b>Education App</b>.'),
              position: 'right'
          }, {
              trigger: '.o-kanban-button-new',
              content: _t("Let's create new student."),
              position: 'bottom'
          }, {
              trigger: 'input[name="name"]',
              extra_trigger: '.o_form_editable',
              content: _t('Set the student name'),
              position: 'right',
          }, {
              trigger: '.o_form_button_save',
              content: _t('Save this record'),
              position: 'bottom',
          }
      ]);
    });
    
  3. Thêm file viin_education_tour.js tới test assets:

    <template id="assets_end" inherit_id="web.assets_backend">
        <xpath expr="." position="inside">
        <script type="text/javascript" src="/viin_education/static/src/js/viin_education_tour.js" />
        </xpath>
    </template>
    
  4. Thêm file /tests/test_tour.py và chạy tour thông qua HttpCase như sau:

    from odoo.tests.common import HttpCase, tagged
    
    @tagged('post_install', '-at_install')
    class TestStudentUI(HttpCase):
    
        def test_01_student_tour(self):
            """Students UI tour test case"""
            self.start_tour("/web", 'education_tour', login="admin")
    

Để chạy kịch bản kiểm thử, cần khởi động lại server với dòng lệnh sau:

./odoo-bin -c ~/project.conf -i viin_education --test-enable

Kiểm tra log sẽ tìm thấy log chạy thành công của test tour:

...INFO test odoo.addons.viin_education.tests.test_tour.TestStudentUI.browser: Tour education_tour succeeded
...INFO test odoo.addons.viin_education.tests.test_tour.TestStudentUI.browser: test successful

Cơ chế hoạt động

Để tạo các kịch bản kiểm thử, đầu tiên bạn cần tạo UI tour trước. Nếu bạn muốn tìm hiểu thêm về các UI tour thì bạn có thể tham khảo thêm tại Web Client Development.

Bước 1, chúng ta cần đăng ký một tour mới với tên eucation_tour. Tour này giống với tour được được hướng dẫn ở phần Web Client Development, trong bước 2, chúng ta thêm các bước cho tour.

Ở đây, chúng ta có 2 sự thay đổi chính so với hướng dẫn trước đó, đầu tiên chúng ta thêm tham số test=True cho định nghĩa một tour, tiếp theo chúng ta thêm 1 thuộc tính run, trong hàm run, bạn phải viết 1 logic để thực thi hoạt động đó, thường được thực hiện bởi người dùng, ví dụ trong bước 4 của tour, chúng ta đã yêu cầu người dùng nhập tên học sinh.

Để tự động hóa bước này, chúng ta thêm hàm run để thiết lập value trong ` trường title. Hàm run vượt qua các tham số tiện ích. Điều này cũng cung cấp một số shortcut để thực hiện hành động cơ bản. Những điều quan trọng nhất như sau:

  • actions.click (element) được sử dụng để click một phần tử.

  • actions.dblclick (element) được sử dụng double-click một phần tử.

  • actions.tripleclick (element) được sử dụng triple-click một phần tử.

  • actions.text (string) được sử dụng thiết lập giá trị đầu vào.

  • actions.drag_and_drop (to, element) được sử dụng kéo thả một phần tử.

  • actions.keydown (keyCodes, element) được sử dụng để kích hoạt các sự kiện keyboard trên một phần tử.

  • actions.auto () là hành động mặc định. Khi không vượt qua được hàm run trong bước tour, actions.auto () sẽ được thực hiện. Điều này thường click phần tử kích hoạt của bước tour. Chỉ có một ngoại lệ là một phần tử đầu vào. Nếu kích hoạt phần tử đầu vào, tour sẽ thiết lập giá trị mặc định Test trong đầu vào. Chính vì điều đó lên chúng ta không cần thêm hàm run cho tất cả các bước.

Ngoài ra, bạn có thể tiến hành toàn bộ hành động theo cách thủ công nếu các hành động mặc định không đủ. Trong bước tiếp theo của tour, chúng ta muốn thiết lập một giá trị cho float range. Lưu ý chúng ta sử dụng các hành động thủ công bởi vì giá trị mặc định không giúp gì được, Do đó, chúng ta đã thêm phương thức run với code jQuery cơ bản để kích vào vào phần tử thứ 3 của float range. Tại đây, bạn sẽ tìm phần tử kích hoạt với thuộc tính this.$anchor.

Mặc định, các tour đã đăng ký được hiển thị cho người dùng cuối để cải thiện trải nghiệm. Để chạy chúng như một kịch bản kiểm thử, bạn cần chạy chúng trong Headless Chrome. Để làm như vậy, bạn cần sử dụng HttpCase Python cho các kịch bản kiểm thử.

Chạy các kịch bản kiểm thử phía client từ UI

Odoo cung cấp cách để chạy các kịch bản kiểm thử phía client từ UI. Bằng cách chạy kịch bản kiểm thử từ UI, bạn sẽ có thể thấy được từng bước của hành động kịch bản kiểm thử. Bằng cách này bạn có thể xác minh rằng kịch bản kiểm thử từ UI đang hoạt động chính xác như mong đợi.

Các bước thực hiện

Bạn có thể chạy tất cả các kịch bản kiểm thử QUnit và kịch bản kiểm thử tour từ UI. Không thể chạy trường kịch bản kiểm thử Python từ UI vì nó chạy phía server. Để xem các tùy chọn chạy các kịch bản kiểm thử từ phía UI, bạn cần bật chế độ phát triển.

Chạy các kịch bản kiểm thử QUnit từ UI

Click Icon con bọ để mở menu, như hình ảnh dưới đây. Click tùy chọn Run JS tests:

Chạy test Js

Thao tác này sẽ mở bộ QUnit và bắt đầu chạy các kịch bản kiểm thử một như trong hình ảnh sau. Theo mặc định nó sẽ hiển thị các kịch bản kiểm thử thất bại. Để hiển thị tất cả các kịch bản kiểm thử thành công, bỏ chọn checkbox Hide passed tests.

Màn hình chạy test js trên giao diện

Chạy các tour từ UI

Click icon con bọ để mở menu, như hình ảnh bên dưới và bắt đầu click Start Tour:

Chạy Tour

Thao tác này sẽ mở cửa sổ hiển thị danh sách các tour như bạn có thể thấy ở hình bên dưới. Click vào nút để chạy các tour:

Màn hình chạy tour trên giao diện

Các kịch bản kiểm thử chỉ hiển thị trong một danh sách nếu bạn bật chế độ để bug asset. Nếu bạn không tìm thấy tour education_tour trong danh sách, bạn hãy kích hoạt chế độ test assets mode.

Cơ chế hoạt động

UI cho QUnit được cung cấp bởi framework QUnit. Tại đây, bạn có thể lọc các kịch bản kiểm thử cho các module. Bạn thậm chí có thể chạy một kịch bản kiểm thử chỉ cho một module. Với UI, bạn có thể xem tiến trình của từng kịch bản kiểm thử và bạn có thể đi sâu vào từng bước của kịch bản kiểm thử. Odoo chỉ mở cùng một URL trong Headless Chrome. Click vào tùy chọn chạy tour sẽ hiển thị danh sách các tour có sẵn.

Danh sách các tour có sẵn sẽ được hiện thông qua việc click tới tùy chọn Run tours. Bằng cách click vào nút trên danh sách, bạn có thể chạy tour. Lưu ý rằng khi tour chạy thông qua tùy chọn trên dòng lệnh, nó sẽ chạy trong một phiên riêng, vì vậy những thay đổi được thực hiện thông qua tour sẽ được phục hồi lại sau khi tour thành công. Tuy nhiên, khi tour chạy từ UI, nó hoạt động giống như người dùng đang vận hành nó, có nghĩa là các thay đổi được thực hiện từ tour không được phục hồi lại, vì vậy hãy sử dụng tùy chọn này một cách cẩn thận.

Gỡ lỗi các kịch bản kiểm thử phía client

Việc phát triển các kịch bản kiểm thử phía client phức tạp là một vấn đề lớn, trong phần này bạn sẽ biết được làm thế nào có thể gỡ lỗi kịch bản kiểm thử phía client trong Odoo. Thay vì chạy tất cả các kịch bản kiểm thử, chúng ta sẽ chỉ chạy một kịch bản kiểm thử. Ngoài ra chúng sẽ hiển thị trên UI của các kịch bản kiểm thử.

Chuẩn bị

Trong phần này, chúng ta sẽ tiếp tục sử dụng module viin_education từ phần trước.

Các bước thực hiện

Thực hiện các bước sau để chạy một kịch bản kiểm thử ở chế độ debug mode:

  1. Mở file /static/tests/float_range.js và cập nhật QUnit.test kiểm tra với QUnit.only như dưới đây:

    ...
    QUnit.only('float_range field test cases', function(assert) {
    ...
    
  2. Thêm tham số debug trong hàm createView:

    var form = await testUtils.createView({
        View: FormView,
        model: 'student',
        data: this.data,
        arch: '<form string="Students">' +
              '<group>' +
                 '<field name="name"/>' +
                 '<field name="rating" widget="float_range" />' +
              '</group>' +
              '</form>',
        res_id: 1,
        debug:true
    });
    

Bật chế độ phát triển và mở menu như hình ở dưới đây rồi chọn Run JS Tests. Thao tác này sẽ mở bộ QUnit:

Chạy test Js

Thao tác này sẽ chạy một kịch bản kiểm thử, đó là kịch bản kiểm thử float_range của chúng ta.

Cơ chế hoạt động

Trong bước 1, chúng ta đã thay thế QUnit.test với QUnit.only. Thao tác này chỉ chạy kịch bản kiểm thử. Trong quá trình phát triển các kịch bản kiểm thử điều này có thể tiết kiệm thời gian. Lưu ý việc sử dụng kịch bản kiểm thử QUnit.only sẽ chỉ dừng lại từ tùy chọn chạy dòng lệnh. Thao tác này chỉ có thể sử dụng cho gỡ lỗi hoặc kịch bản kiểm thử và nó chỉ làm việc khi bạn mở một kịch bản kiểm thử từ UI, vì vậy đừng quên thay thế nó với QUnit.test sau khi phát triển.

Trong ví dụ kịch bản kiểm thử QUnit từ UI, bạn biết rằng bạn không thể xem các dạng giao diện form trong UI. Từ UI của bộ QUnit, bạn chỉ có thể thấy các log. Điều này làm cho việc phát triển một kịch bản kiểm thử QUnit trở nên vô cùng khó khăn. Để xử lý vấn đề này, sử dụng tham số debug trong hàm createView. Trong bước 2, chúng ta thêm debug: true trong hàm createView. Điều này sẽ hiển thị kịch bản kiểm thử giao diện form trong trình duyệt.

Warning

Vào cuối kịch bản kiểm thử, chúng ta hủy giao diện thông qua phương thức destroy(). Nếu bạn đã hủy chế độ view thì bạn không thể xem giao diện form trong UI, do vậy đề xem nó trong trình duyệt, hãy xóa bỏ dòng đó trong quá trình phát triển. Điều này sẽ giúp bạn trong việc gỡ lỗi kịch bản kiểm thử.

Chạy các kịch bản kiểm thử QUnit trong chế độ debug mode giúp bạn phát triển các kịch bản kiểm thử một cách dễ dàng và nhanh chóng.

Tạo Video / Ảnh chụp màn hình để kiểm tra các kịch bản kiểm thử thất bại

Odoo sử dụng Headless Chrome. Điều này mở ra những khả năng mới. Bắt đầu từ phiên bản Odoo 12, bạn có thể ghi Video của các kịch bản kiểm thử thất bại hoặc chụp ảnh các kịch bản kiểm thử thất bại.

Các bước thực hiện

Việc quay video cho các kịch bản kiểm thử cần phải cài đặt gói ffmpeg.

  1. Để cài đặt thư viện này, bạn cần thực hiện câu lệnh sau:

    apt-get install ffmpeg
    
  2. Để tạo video hoặc chụp ảnh, bạn cần cung cấp địa chỉ thư mục để lưu trữ video hoặc hình ảnh đó.

  3. Nếu bạn muốn tạo screencast (video) của một kịch bản kiểm thử, sử dụng lệnh --screencasts:

    ./odoo-bin -c ~/project.conf -i viin_education --test-enable --screencasts=/home/pga/viin_odoo_test/
    
  4. Nếu bạn muốn tạo ảnh chụp màn hình của một kịch bản kiểm thử, hãy sử dụng lệnh --screenshots:

    ./odoo-bin -c ~/project.conf -i viin_education --test-enable --screenshots=/home/pga/viin_odoo_test/
    

Cơ chế hoạt động

Để tạo ảnh chụp màn hình / quay video màn hình cho các kịch bản kiểm thử thất bại, bạn cần chạy server với đường dẫn để lưu file video hoặc ảnh. Khi bạn chạy kịch bản kiểm thử và nếu 1 kịch bản kiểm thử thất bại, Odoo sẽ lưu ảnh/video của các thất bại trong thư mục đó.

Để tạo một video cho các trường hợp kịch bản kiểm thử, Odoo sử dụng gói ffmpeg. Nếu bạn không cài gói đó thì bạn chỉ có thể chụp ảnh màn hình với các kịch bản kiểm thử thất bại. Sau khi cài đặt gói, bạn có thể thấy file mp4 của bất kỳ kịch bản kiểm thử nào thất bại.

Note

Việc tạo video cho các kịch bản kiểm thử có thể tiêu tốn nhiều dung lượng ở đĩa, vì vậy hãy sử dụng tùy chọn này khi thật cần thiết.

Hãy luôn nhớ rằng việc chụp ảnh màn hình hay quay video chỉ được tạo cho các kịch bản kiểm thử thất bại, vì vậy nếu bạn muốn kiểm tra chúng hãy viết 1 kịch bản kiểm thử thất bại.

Nhập dữ liệu ngẫu nhiên để kịch bản kiểm thử

Cho đến hiện tại, chúng ta đã thấy các kịch bản kiểm thử được sử dụng để phát hiện lỗi hoặc lỗi nghiệp vụ. Tuy nhiên, đôi khi chúng ta cần phải tự kịch bản kiểm thử các tính năng của mình với số lượng dữ liệu lớn. Việc tạo ra một lượng lớn dữ liệu là một công việc tẻ nhạt. Odoo cung cấp một bộ công cụ giúp bạn tạo ra nhiều dữ liệu ngẫu nhiên cho model của mình. Trong phần này, chúng ta sử dụng lệnh populate để tạo dữ liệu kịch bản kiểm thử cho model education.student.

Chuẩn bị

Trong phần này, chúng ta sẽ tiếp tục sử dụng module viin_education từ phần trước. Chúng ta sẽ thêm phương thức _populate_factories, phương thức này sẽ được sử dụng để tạo các dữ liệu kịch bản kiểm thử.

Các bước thực hiện

  1. Thêm một thư mục populate trong module viin_education. Thêm một file __init__.py với nội dung này:

    from . import education_data
    
  2. Thêm một file viin_education/popuplate/education_data.py và thêm đoạn code vào để tạo dữ liệu học sinh:

    from odoo import models
    from odoo.tools import populate
    
    class StudentData(models.Model)
        _inherit = 'education.student'
    
        _populate_sizes = {'small': 10, 'medium': 100, 'large': 500}
    
        def _populate_factories(self):
            return [('name', populate.constant('Student no {counter}')),]
    
  3. Chạy lệnh dưới đây để tạo dữ liệu cho học sinh:

    ./odoo-bin populate --models=education.student --size=medium -c ~/project.conf -i viin_education
    

Điều này sẽ tạo ra 100 đơn vị dữ liệu học sinh. Sau khi tạo dữ liệu, quá trình sẽ được kết thúc. Để xem dữ liệu của học sinh, hãy chạy lệnh mà không điền tham số.

Cơ chế hoạt động

Trong bước 1, chúng ta thêm thư mục populate trong module viin_education. Thư mục chứa code để điền dữ liệu kịch bản kiểm thử. Trong bước 2, chúng ta thêm code tạo dữ liệu học sinh. Việc tạo dữ liệu một cách ngẫu nhiên, cần sử dụng phương thức populate_factories. Phương thức _populate_factories trả về dữ liệu cho các trường trong model, sẽ được sử dụng để tạo dữ liệu ngẫu nhiên. Model education.student có trường name bắt buộc, vì vậy trong ví dụ chúng ta sẽ tạo giá trị cho trường name. Trình tạo này sẽ được sử dụng để tạo dữ liệu ngẫu nhiên cho hồ sơ học sinh. Chúng ta đã sử dụng populate.constant cho trường tên, điều này sẽ được tạo ra các tên khác nhau khi chúng ta lặp lại trong quá trình tạo dữ liệu.

Tương tự như populate.constant, Odoo cũng cung cấp một và trình tạo dữ liệu khác nhau. Dưới đây danh sách một số trình đó:

  • populate.randomize(list) sẽ trả về các phần tử ngẫu nhiên từ một danh sách đã cho.

  • populate.cartesian(list) cũng giống randomize(), nhưng nó sẽ cố gắng trả bao gồm tất cả các giá trị từ danh sách.

  • populate.iterate(list) sẽ lặp lại trên một danh sách nhất định và khi tất cả các phần tử được lặp lại, nó sẽ trả về dựa trên các phần tử ngẫu nhiên hoặc randomize.

  • populate.constant(str) được sử dụng để tạo chuỗi được định dạng, bạn cũng có thể chuyền tham số formatter cho các giá trị định dạng, theo mặc định trình định dạng là hàm định dạng chuỗi.

  • populate.compute(function) được sử dụng khi bạn muốn tính toán một giá trị dựa trên hàm của bạn.

  • populate.randint(a, b) được sử dụng để tạo ra một số ngẫu nhiên giữa 2 tham số a và b.

Các trình tạo này có thể được sử dụng để tạo dữ liệu kịch bản kiểm thử do bạn lựa chọn. Một thuộc tính quan trọng khác là _populate_sizes. Nó được sử dụng để xác định số lượng bản ghi bạn muốn tạo dựa trên tham số -size. Giá trị của nó phụ thuộc vào đối tượng nghiệp vụ.

Trong bước 3, chúng ta đã tạo dữ liệu cho model học sinh. Để điền dữ liệu kịch bản kiểm thử, bạn sẽ cần sử dụng tham số --size--model. Odoo sử dụng phương thức _populate để tạo bản ghi ngẫu nhiên. Phương thức _populate nó sử dụng _populate_factories để lấy ra dữ liệu ngẫu nhiên cho bản ghi. Phương thức _populate sẽ tạo dữ liệu cho các model được cung cấp trong tham số --model và lượng dữ liệu thử nghiệm sẽ dựa trên thuộc tính _populate_sizes của model. Dựa trên ví dụ, nếu chúng ta đang sử dụng --size=medium, dữ liệu cho 100 học sinh sẽ được tạo.

Note

Nếu bạn chạy lệnh populate nhiều lần, dữ liệu sẽ được tạo nhiều lần. Phải sử dụng điều này một cách cẩn thận: nếu bạn chạy lệnh trong cơ sở dữ liệu thực tế đang sử dụng, nó sẽ tạo dữ liệu kịch bản kiểm thử cơ sở dữ liệu. Điều này là việc bạn cần tránh.

Đôi khi, bạn cũng muốn tạo dữ liệu quan hệ. Ví dụ: với học sinh, bạn cũng có thể tạo Lớp học. Để quản lý các bản ghi như vậy, bạn có thể sử dụng thuộc tính _populate_dependencies:

class StudentData(models.Model):
     _inherit = 'education.student'

     _populate_sizes = {'small': 10, 'medium': 100, 'large': 500}
     _populate_dependencies = ['education.class']
     ...

Việc này sẽ điền dữ liệu cho các phụ thuộc trước khi điền vào model. Sau khi hoàn tất, bạn có thể truy cập dữ liệu được điền thông qua sổ đăng ký populated_models:

class_ids = self.env.registry.populated_models['education.class']

Đoạn code đưa ra ở đây sẽ cung cấp cho bạn danh sách các lớp học được điền trước khi tạo dữ liệu kiểm thử cho model hiện tại.