Ví dụ python kiểm tra đơn vị giả

Chế giễu có thể khó hiểu. Khi tôi đang kiểm tra mã mà tôi đã viết, tôi muốn xem liệu mã có thực hiện những gì nó phải làm từ đầu đến cuối không. Tôi thường bắt đầu nghĩ về một bài kiểm tra tích hợp, chức năng, nơi tôi nhập thông tin đầu vào thực tế và nhận được đầu ra thực tế. Tôi truy cập mọi hệ thống thực mà mã của tôi sử dụng để đảm bảo tương tác giữa các hệ thống đó đang hoạt động bình thường, sử dụng đối tượng thực và lệnh gọi API thực. Mặc dù các loại thử nghiệm này là cần thiết để xác minh rằng các hệ thống phức tạp đang hoạt động tốt với nhau, nhưng chúng không phải là thứ chúng tôi muốn từ các thử nghiệm đơn vị

 

Các bài kiểm tra đơn vị là kiểm tra lớp ngoài cùng của mã. Các bài kiểm tra tích hợp là cần thiết, nhưng các bài kiểm tra đơn vị tự động mà chúng tôi chạy sẽ không đạt được mức độ tương tác hệ thống sâu như vậy. Điều này có nghĩa là bất kỳ lệnh gọi API nào trong chức năng mà chúng tôi đang thử nghiệm đều có thể và nên được mô phỏng. Chúng ta nên thay thế bất kỳ lệnh gọi API hoặc tạo đối tượng không cần thiết nào bằng một lệnh gọi hoặc đối tượng giả. Điều này cho phép chúng tôi tránh sử dụng tài nguyên không cần thiết, đơn giản hóa việc khởi tạo các thử nghiệm của chúng tôi và giảm thời gian chạy của chúng. Hãy nghĩ đến việc thử nghiệm một chức năng truy cập API HTTP bên ngoài. Thay vì đảm bảo rằng máy chủ thử nghiệm có sẵn để gửi phản hồi chính xác, chúng tôi có thể thử thư viện HTTP và thay thế tất cả các lệnh gọi HTTP bằng các lệnh gọi giả. Điều này làm giảm sự phụ thuộc và độ phức tạp của thử nghiệm, đồng thời cho phép chúng tôi kiểm soát chính xác những gì thư viện HTTP trả về, điều này có thể khó thực hiện nếu không

Chúng ta có ý gì khi chế giễu?

 

Thuật ngữ chế nhạo được sử dụng rất nhiều, nhưng tài liệu này sử dụng định nghĩa sau

 

"Việc thay thế một hoặc nhiều lời gọi hàm hoặc đối tượng bằng lời gọi hoặc đối tượng giả"

 

Một lệnh gọi hàm giả trả về một giá trị được xác định trước ngay lập tức mà không thực hiện bất kỳ công việc nào. Các thuộc tính và phương thức của đối tượng mô phỏng được xác định hoàn toàn tương tự trong thử nghiệm mà không cần tạo đối tượng thực hoặc thực hiện bất kỳ công việc nào. Thực tế là người viết bài kiểm tra có thể xác định các giá trị trả về của mỗi lệnh gọi hàm mang lại cho người đó một lượng sức mạnh to lớn khi kiểm tra, nhưng điều đó cũng có nghĩa là người đó cần thực hiện một số công việc cơ bản để thiết lập mọi thứ đúng cách.

 

Trong Python, việc chế nhạo được thực hiện thông qua mô-đun

[in my_module.py] 
from module import ClassA
0. Mô-đun chứa một số lớp và hàm hữu ích, trong đó quan trọng nhất là hàm
[in my_module.py] 
from module import ClassA
1 [với vai trò trang trí và quản lý ngữ cảnh] và lớp
[in my_module.py] 
from module import ClassA
2. Mocking trong Python phần lớn được thực hiện thông qua việc sử dụng hai thành phần mạnh mẽ này

 

Chúng ta KHÔNG có ý gì bằng cách chế nhạo?

 

Các nhà phát triển sử dụng nhiều đối tượng hoặc mô-đun "giả", là những thay thế cục bộ đầy đủ chức năng cho các dịch vụ và API được nối mạng. Ví dụ: thư viện

[in my_module.py] 
from module import ClassA
3 là thư viện
[in my_module.py] 
from module import ClassA
4 giả thu thập tất cả các lệnh gọi API của
[in my_module.py] 
from module import ClassA
4 và xử lý chúng cục bộ. Mặc dù các mô phỏng này cho phép các nhà phát triển thử nghiệm cục bộ các API bên ngoài, nhưng chúng vẫn yêu cầu tạo các đối tượng thực. Đây không phải là kiểu chế giễu được đề cập trong tài liệu này. Tài liệu này đặc biệt về việc sử dụng các đối tượng
[in my_module.py] 
from module import ClassA
2 để quản lý đầy đủ luồng điều khiển của chức năng được kiểm tra, cho phép dễ dàng kiểm tra lỗi và xử lý ngoại lệ

 

Làm cách nào để chúng tôi mô phỏng bằng Python?

 

Mocking trong Python được thực hiện bằng cách sử dụng

[in my_module.py] 
from module import ClassA
1 để chiếm quyền điều khiển một chức năng API hoặc lệnh gọi tạo đối tượng. Khi
[in my_module.py] 
from module import ClassA
1 chặn một cuộc gọi, nó sẽ trả về một đối tượng
[in my_module.py] 
from module import ClassA
2 theo mặc định. Bằng cách đặt các thuộc tính trên đối tượng
[in my_module.py] 
from module import ClassA
2, bạn có thể mô phỏng lệnh gọi API để trả về bất kỳ giá trị nào bạn muốn hoặc tăng
[in my_module.py] 
from module import ClassA
11

 

Quy trình chung như sau

 

  1. Viết bài kiểm tra như thể bạn đang sử dụng các API bên ngoài thực sự
  2. Trong hàm đang thử nghiệm, hãy xác định lệnh gọi API nào cần được mô phỏng;
  3. Trong chức năng kiểm tra, hãy vá các cuộc gọi API
  4. Thiết lập phản hồi đối tượng
    [in my_module.py] 
    from module import ClassA
    2
  5. Chạy thử nghiệm của bạn

 

Nếu bài kiểm tra của bạn vượt qua, bạn đã hoàn thành. Nếu không, bạn có thể gặp lỗi trong chức năng đang được kiểm tra hoặc bạn có thể đã thiết lập phản hồi

[in my_module.py] 
from module import ClassA
2 không chính xác. Tiếp theo, chúng ta sẽ đi vào chi tiết hơn về các công cụ mà bạn sử dụng để tạo và định cấu hình mô hình

[in my_module.py] 
from module import ClassA
4

 

[in my_module.py] 
from module import ClassA
1 có thể được sử dụng làm công cụ trang trí cho hàm kiểm tra, lấy một chuỗi đặt tên hàm sẽ được vá làm đối số. Để
[in my_module.py] 
from module import ClassA
1 xác định vị trí chức năng được vá, chức năng này phải được chỉ định bằng tên đủ điều kiện của nó, đây có thể không phải là điều bạn mong đợi. Nếu một lớp được nhập bằng cách sử dụng câu lệnh
[in my_module.py] 
from module import ClassA
16, thì
[in my_module.py] 
from module import ClassA
17 sẽ trở thành một phần của không gian tên của mô-đun mà nó được nhập vào

 

Ví dụ: nếu một lớp được nhập trong mô-đun

[in my_module.py] 
from module import ClassA
18 như sau

 

[in my_module.py] 
from module import ClassA

 

Nó phải được vá thành

[in my_module.py] 
from module import ClassA
19, thay vì
[in my_module.py] 
from module import ClassA
20, do ngữ nghĩa của câu lệnh
[in my_module.py] 
from module import ClassA
21, câu lệnh nhập các lớp và hàm vào không gian tên hiện tại

 

Thông thường,

[in my_module.py] 
from module import ClassA
1 được sử dụng để vá một lệnh gọi API bên ngoài hoặc bất kỳ lệnh gọi chức năng hoặc tạo đối tượng nào khác tốn nhiều thời gian hoặc tài nguyên. Bạn chỉ nên vá một số lệnh gọi cho mỗi lần kiểm tra. Nếu bạn thấy mình đang thử
[in my_module.py] 
from module import ClassA
1 nhiều lần, hãy cân nhắc tái cấu trúc bài kiểm tra của bạn hoặc chức năng bạn đang kiểm tra

 

Sử dụng trình trang trí

[in my_module.py] 
from module import ClassA
1 sẽ tự động gửi đối số vị trí đến chức năng bạn đang trang trí [i. e. , chức năng kiểm tra của bạn]. Khi vá nhiều chức năng, trình trang trí gần nhất với chức năng được trang trí sẽ được gọi trước, do đó, nó sẽ tạo đối số vị trí đầu tiên

 

[in my_module.py] 
from module import ClassA
1

 

Theo mặc định, các đối số này là phiên bản của

[in my_module.py] 
from module import ClassA
2, là đối tượng chế nhạo mặc định của
[in my_module.py] 
from module import ClassA
0. Bạn có thể xác định hành vi của hàm đã vá bằng cách đặt các thuộc tính trên phiên bản
[in my_module.py] 
from module import ClassA
2 được trả về

 

 

MagicMock

 

Các đối tượng

[in my_module.py] 
from module import ClassA
2 cung cấp một giao diện mô phỏng đơn giản cho phép bạn đặt giá trị trả về hoặc hành vi khác của lệnh gọi hàm hoặc tạo đối tượng mà bạn đã vá. Điều này cho phép bạn xác định đầy đủ hành vi của cuộc gọi và tránh tạo các đối tượng thực, điều này có thể gây khó khăn. Ví dụ: nếu chúng tôi đang vá một lệnh gọi tới
[in my_module.py] 
from module import ClassA
29, một lệnh gọi thư viện HTTP, thì chúng tôi có thể xác định phản hồi cho lệnh gọi đó sẽ được trả về khi lệnh gọi API được thực hiện trong chức năng đang thử nghiệm, thay vì đảm bảo rằng máy chủ thử nghiệm được

 

Hai thuộc tính quan trọng nhất của phiên bản

[in my_module.py] 
from module import ClassA
2 là
[in my_module.py] 
from module import ClassA
41 và
[in my_module.py] 
from module import ClassA
42, cả hai thuộc tính này đều cho phép chúng tôi xác định hành vi trả về của lệnh gọi đã vá lỗi

 

return_value

 

Thuộc tính

[in my_module.py] 
from module import ClassA
41 trên phiên bản
[in my_module.py] 
from module import ClassA
2 được chuyển vào hàm kiểm tra của bạn cho phép bạn chọn kết quả trả về có thể gọi được đã vá. Trong hầu hết các trường hợp, bạn sẽ muốn trả về một phiên bản giả của phiên bản có thể gọi được thường trả về. Đây có thể là JSON, một lần lặp, một giá trị, một thể hiện của đối tượng phản hồi thực, một
[in my_module.py] 
from module import ClassA
2 giả làm đối tượng phản hồi hoặc bất kỳ thứ gì khác. Khi vá các đối tượng, lệnh gọi được vá là lệnh gọi tạo đối tượng, do đó,
[in my_module.py] 
from module import ClassA
41 của
[in my_module.py] 
from module import ClassA
2 phải là một đối tượng giả, có thể là một
[in my_module.py] 
from module import ClassA
2 khác

Nếu mã bạn đang kiểm tra là Pythonic và gõ vịt thay vì gõ rõ ràng, thì việc sử dụng

[in my_module.py] 
from module import ClassA
2 làm đối tượng phản hồi có thể thuận tiện. Thay vì gặp rắc rối khi tạo một thể hiện thực của một lớp, bạn có thể định nghĩa các cặp khóa-giá trị thuộc tính tùy ý trong hàm tạo
[in my_module.py] 
from module import ClassA
2 và chúng sẽ tự động được áp dụng cho thể hiện

 

[in my_module.py] 
from module import ClassA
2

 

Lưu ý rằng đối số được chuyển đến

[in my_module.py] 
from module import ClassA
51, tôi. e. ,
[in my_module.py] 
from module import ClassA
52, là một
[in my_module.py] 
from module import ClassA
2 và chúng tôi đang đặt
[in my_module.py] 
from module import ClassA
41 thành một
[in my_module.py] 
from module import ClassA
2 khác. Khi chế giễu, mọi thứ đều là
[in my_module.py] 
from module import ClassA
2

 

Chỉ định một MagicMock

 

Mặc dù tính linh hoạt của

[in my_module.py] 
from module import ClassA
2 thuận tiện cho việc mô phỏng nhanh các lớp có yêu cầu phức tạp, nhưng nó cũng có thể là nhược điểm. Theo mặc định, các
[in my_module.py] 
from module import ClassA
2 hoạt động như thể chúng có bất kỳ thuộc tính nào, kể cả những thuộc tính mà bạn không muốn chúng có. Trong ví dụ trên, chúng tôi trả về đối tượng
[in my_module.py] 
from module import ClassA
2 thay vì đối tượng
[in my_module.py] 
from module import ClassA
40. Tuy nhiên, giả sử chúng ta đã mắc lỗi trong lệnh gọi
[in my_module.py] 
from module import ClassA
1 và đã vá một hàm được cho là trả về một đối tượng
[in my_module.py] 
from module import ClassA
42 thay vì một đối tượng
[in my_module.py] 
from module import ClassA
40.
[in my_module.py] 
from module import ClassA
2 mà chúng ta trả về sẽ vẫn hoạt động như thể nó có tất cả các thuộc tính của đối tượng
[in my_module.py] 
from module import ClassA
42, mặc dù chúng ta muốn nó mô hình hóa một đối tượng
[in my_module.py] 
from module import ClassA
40. Điều này có thể dẫn đến lỗi kiểm tra khó hiểu và hành vi kiểm tra không chính xác

 

Giải pháp cho vấn đề này là ________ 547 trong

[in my_module.py] 
from module import ClassA
2 khi tạo nó, sử dụng đối số từ khóa ________ 547.
[in my_module.py] 
from module import ClassA
40. Điều này tạo ra một
[in my_module.py] 
from module import ClassA
2 sẽ chỉ cho phép truy cập vào các thuộc tính và phương thức trong lớp mà từ đó
[in my_module.py] 
from module import ClassA
2 được xác định. Cố gắng truy cập một thuộc tính không có trong đối tượng ban đầu sẽ làm tăng
[in my_module.py] 
from module import ClassA
43, giống như đối tượng thực sẽ. Một ví dụ đơn giản là

 

[in my_module.py] 
from module import ClassA
4

 

tác dụng phụ

 

Đôi khi, bạn sẽ muốn kiểm tra xem hàm của mình có xử lý chính xác một ngoại lệ hay không hoặc nhiều lệnh gọi của hàm bạn đang vá có được xử lý chính xác không. Bạn có thể làm điều đó bằng cách sử dụng

[in my_module.py] 
from module import ClassA
42. Đặt
[in my_module.py] 
from module import ClassA
42 thành một ngoại lệ sẽ tăng ngoại lệ đó ngay lập tức khi chức năng được vá được gọi

 

Đặt

[in my_module.py] 
from module import ClassA
42 thành một iterable sẽ trả về mục tiếp theo từ iterable mỗi khi chức năng được vá được gọi. Đặt
[in my_module.py] 
from module import ClassA
42 thành bất kỳ giá trị nào khác sẽ trả về giá trị đó

 

[in my_module.py] 
from module import ClassA
5

 

khẳng định_gọi_với

 

[in my_module.py] 
from module import ClassA
48 khẳng định rằng hàm đã vá đã được gọi với các đối số được chỉ định làm đối số cho
[in my_module.py] 
from module import ClassA
48

 

[in my_module.py] 
from module import ClassA
4

 

Một ví dụ đầy đủ

 

Trong ví dụ này, tôi đang thử nghiệm hàm

[in my_module.py] 
from module import ClassA
70 trên
[in my_module.py] 
from module import ClassA
71. Điều này có nghĩa là lệnh gọi API trong
[in my_module.py] 
from module import ClassA
72 sẽ được thực hiện hai lần, đây là thời điểm tuyệt vời để sử dụng
[in my_module.py] 
from module import ClassA
73

 

Mã đầy đủ của ví dụ ở đây

 

[in my_module.py] 
from module import ClassA
4

 

Tôi đang vá hai cuộc gọi trong chức năng đang được kiểm tra [

[in my_module.py] 
from module import ClassA
74], một đến
[in my_module.py] 
from module import ClassA
75 và một đến
[in my_module.py] 
from module import ClassA
76. Vì tôi đang vá hai cuộc gọi, tôi nhận được hai đối số cho hàm kiểm tra của mình, mà tôi đã gọi là
[in my_module.py] 
from module import ClassA
77 và
[in my_module.py] 
from module import ClassA
78. Đây là cả hai đối tượng
[in my_module.py] 
from module import ClassA
2. Ở trạng thái mặc định, họ không làm gì nhiều. Chúng ta cần chỉ định một số hành vi phản hồi cho họ

 

[in my_module.py] 
from module import ClassA
7

 

Thử nghiệm này để đảm bảo rằng cơ sở thử lại cuối cùng cũng hoạt động, vì vậy tôi sẽ gọi cập nhật nhiều lần và thực hiện nhiều cuộc gọi tới

[in my_module.py] 
from module import ClassA
75 và
[in my_module.py] 
from module import ClassA
76

 

Ở đây tôi thiết lập các

[in my_module.py] 
from module import ClassA
42 mà tôi muốn. Tôi muốn tất cả các cuộc gọi tới
[in my_module.py] 
from module import ClassA
75 hoạt động [trả lại một
[in my_module.py] 
from module import ClassA
34 trống là tốt cho bài kiểm tra này], cuộc gọi đầu tiên tới
[in my_module.py] 
from module import ClassA
76 không thành công với một ngoại lệ và cuộc gọi thứ hai tới
[in my_module.py] 
from module import ClassA
76 hoạt động. Loại kiểm soát chi tiết đối với hành vi này chỉ có thể thực hiện được thông qua chế nhạo

 

[in my_module.py] 
from module import ClassA
3

 

Khi tôi đã thiết lập xong các

[in my_module.py] 
from module import ClassA
42, phần còn lại của bài kiểm tra rất đơn giản. hành vi là. cuộc gọi đầu tiên tới
[in my_module.py] 
from module import ClassA
76 không thành công, vì vậy cơ sở thử lại bao bọc
[in my_module.py] 
from module import ClassA
39 sẽ phát hiện lỗi và mọi thứ sẽ hoạt động lần thứ hai. Hành vi này có thể được xác minh thêm bằng cách kiểm tra lịch sử cuộc gọi của
[in my_module.py] 
from module import ClassA
78 và
[in my_module.py] 
from module import ClassA
77

Sự kết luận

 

Việc sử dụng các đối tượng giả một cách chính xác đi ngược lại trực giác của chúng ta để làm cho các bài kiểm tra thực tế và kỹ lưỡng nhất có thể, nhưng làm như vậy sẽ cho chúng ta khả năng viết các bài kiểm tra độc lập chạy nhanh, không phụ thuộc. Nó cung cấp cho chúng tôi sức mạnh để kiểm tra xử lý ngoại lệ và các trường hợp cạnh mà nếu không thì không thể kiểm tra. Quan trọng nhất, nó cho phép chúng tôi tự do tập trung nỗ lực thử nghiệm vào chức năng của mã, thay vì khả năng thiết lập môi trường thử nghiệm. Bằng cách tập trung vào kiểm tra những gì quan trọng, chúng tôi có thể cải thiện phạm vi kiểm tra và tăng độ tin cậy của mã, đó là lý do tại sao chúng tôi kiểm tra ngay từ đầu

Thử nghiệm đơn vị với ví dụ Python là gì?

Kiểm tra đơn vị là phương pháp kiểm tra phần mềm xem xét các đoạn mã nhỏ nhất có thể kiểm tra được, được gọi là đơn vị, được kiểm tra để hoạt động chính xác . Bằng cách thực hiện kiểm tra đơn vị, chúng tôi có thể xác minh rằng từng phần của mã, bao gồm các chức năng của trình trợ giúp có thể không được hiển thị cho người dùng, hoạt động chính xác và như dự định.

Sự khác biệt giữa giả và MagicMock là gì?

Vậy sự khác biệt giữa chúng là gì? . Nó chứa tất cả các phương pháp ma thuật được tạo sẵn và sẵn sàng để sử dụng [e. g. __str__ , __len__ , v.v. ]. Do đó, bạn nên sử dụng MagicMock khi cần các phương thức ma thuật và Mock nếu không cần. MagicMock is a subclass of Mock . It contains all magic methods pre-created and ready to use [e.g. __str__ , __len__ , etc.]. Therefore, you should use MagicMock when you need magic methods, and Mock if you don't need them.

Bạn có thể giả lập các biến trong Python không?

Với biến mô-đun, bạn có thể đặt giá trị trực tiếp hoặc sử dụng mô hình .

Chủ Đề