Tác dụng phụ giả của Python không hoạt động

Thay vì TDD (Phát triển theo hướng kiểm tra) buộc bạn phải nghĩ về các bài kiểm tra trước, người ta có thể thực hành TPD (Phát triển song song kiểm tra). Trong TPD, bạn bắt đầu với việc phát triển mã, nhưng trong quá trình phát triển, bạn kiểm tra tính chính xác của mã bằng cách viết các bài kiểm tra và thực thi chúng (thay vì chạy mã trực tiếp hoặc sử dụng bảng điều khiển)

Đối với một vài ví dụ tiếp theo, chúng tôi sẽ sử dụng ________ 09 để chứng minh/giải thích đối tượng ________ 07 nói về điều gì

Unittest đã được tích hợp sẵn trong thư viện chuẩn của Python kể từ phiên bản 2. 1. Bạn có thể sẽ thấy nó trong các ứng dụng Python thương mại và các dự án mã nguồn mở

Hãy tạo một http nhận yêu cầu như sau với gói yêu cầu

import requests

my_requests = requests
my_response = my_requests.get("http://www.google.com")
my_response.status_code
my_response.url

"""
200
'http://www.google.com/'
"""

Để hiểu rõ hơn về đối tượng _______ 31, chúng ta hãy thay đổi ví dụ trên

from unittest.mock import Mock

my_requests = Mock()
my_response = my_requests.get("http://www.google.com")
my_response.status_code
my_response.url

"""


"""

Điều đó thật lạ. Nó trả về một đối tượng giả, hãy điều tra thêm

type(my_response)

"""
unittest.mock.Mock
"""

phương pháp giả

Điều gì về các phương pháp bạn có thể gọi trên nó?

dir(my_requests)

"""
['assert_any_call',
 'assert_called',
 'assert_called_once',
 'assert_called_once_with',
 'assert_called_with',
 'assert_has_calls',
 'assert_not_called',
 'attach_mock',
 'call_args',
 'call_args_list',
 'call_count',
 'called',
 'configure_mock',
 'method_calls',
 'mock_add_spec',
 'mock_calls',
 'reset_mock',
 'return_value',
 'side_effect']
 """

Ồ. Có vẻ như rất nhiều để tiêu hóa.

Tác dụng phụ giả của Python không hoạt động

Đừng lo, chúng ta sẽ xem xét một số trong số chúng trong các phiên và nhanh chóng xem chúng hợp lệ như thế nào hoặc được sử dụng để thử nghiệm như thế nào

Khi bạn chạy phương thức

type(my_response)

"""
unittest.mock.Mock
"""
2 và sau đó sử dụng đối tượng

________số 8

Chúng tôi vừa xác minh rằng đối tượng

type(my_response)

"""
unittest.mock.Mock
"""
3 với phương thức
type(my_response)

"""
unittest.mock.Mock
"""
4 đã được gọi và nó đã được gọi với các đối số chính xác

Một ví dụ đơn giản

So sánh những điều sau đây và tự mình thử mà không chế nhạo

from unittest.mock import Mock

my_requests = Mock()
my_response = my_requests.get("http://www.google.com")
my_response.status_code
my_response.url

"""


"""
1

Thế còn (các) phương thức gọi bên dưới đối tượng

type(my_response)

"""
unittest.mock.Mock
"""
1 thì sao?

from unittest.mock import Mock

my_requests = Mock()
my_response = my_requests.get("http://www.google.com")
my_response.status_code
my_response.url

"""


"""
3

Bạn có thể bắt đầu thấy tại sao điều này sẽ hữu ích khi xác minh rằng các chức năng của bạn sẽ được gọi chính xác không?

Điều gì sẽ xảy ra nếu bạn muốn giả lập một số giá trị từ một hàm hoặc một phương thức?

Quan sát

from unittest.mock import Mock

my_requests = Mock()
my_response = my_requests.get("http://www.google.com")
my_response.status_code
my_response.url

"""


"""
4

Giả sử bạn muốn sử dụng phương thức

type(my_response)

"""
unittest.mock.Mock
"""
6 và trả về một đối tượng bằng
type(my_response)

"""
unittest.mock.Mock
"""
7 và
type(my_response)

"""
unittest.mock.Mock
"""
8, bạn có thể xác định giá trị trả về bằng đối tượng
type(my_response)

"""
unittest.mock.Mock
"""
1

from unittest.mock import Mock

my_requests = Mock()
my_response = my_requests.get("http://www.google.com")
my_response.status_code
my_response.url

"""


"""
9

Điều này khó giải thích hơn một chút, nhưng trước tiên hãy xem xét ví dụ "không chế nhạo" này

import requests

my_requests = requests
my_response = my_requests.get("http://www.google.com")
my_response.status_code
my_response.url

"""
200
'http://www.google.com/'
"""
0

Bây giờ, giả sử chúng tôi muốn chế nhạo một

dir(my_requests)

"""
['assert_any_call',
 'assert_called',
 'assert_called_once',
 'assert_called_once_with',
 'assert_called_with',
 'assert_has_calls',
 'assert_not_called',
 'attach_mock',
 'call_args',
 'call_args_list',
 'call_count',
 'called',
 'configure_mock',
 'method_calls',
 'mock_add_spec',
 'mock_calls',
 'reset_mock',
 'return_value',
 'side_effect']
 """
0 vì chúng tôi không có quyền truy cập internet (hoặc bất kỳ lý do nào khác)

import requests

my_requests = requests
my_response = my_requests.get("http://www.google.com")
my_response.status_code
my_response.url

"""
200
'http://www.google.com/'
"""
1

Tác dụng phụ như một máy phát điện

Một trường hợp sử dụng tốt khác về tác dụng phụ là khi một danh sách được cung cấp, nó sẽ cung cấp một đối tượng

dir(my_requests)

"""
['assert_any_call',
 'assert_called',
 'assert_called_once',
 'assert_called_once_with',
 'assert_called_with',
 'assert_has_calls',
 'assert_not_called',
 'attach_mock',
 'call_args',
 'call_args_list',
 'call_count',
 'called',
 'configure_mock',
 'method_calls',
 'mock_add_spec',
 'mock_calls',
 'reset_mock',
 'return_value',
 'side_effect']
 """
1

import requests

my_requests = requests
my_response = my_requests.get("http://www.google.com")
my_response.status_code
my_response.url

"""
200
'http://www.google.com/'
"""
2

Điều này trở nên hữu ích khi bạn muốn mô phỏng một luồng có nhiều yêu cầu

import requests

my_requests = requests
my_response = my_requests.get("http://www.google.com")
my_response.status_code
my_response.url

"""
200
'http://www.google.com/'
"""
3

Khi tác dụng phụ và giá trị trả về đều được chỉ định, tác dụng phụ sẽ được ưu tiên. Thông tin bổ sung tại đây

Khi sử dụng python, việc sử dụng các đối tượng (lớp) có thể phổ biến và khi sử dụng

dir(my_requests)

"""
['assert_any_call',
 'assert_called',
 'assert_called_once',
 'assert_called_once_with',
 'assert_called_with',
 'assert_has_calls',
 'assert_not_called',
 'attach_mock',
 'call_args',
 'call_args_list',
 'call_count',
 'called',
 'configure_mock',
 'method_calls',
 'mock_add_spec',
 'mock_calls',
 'reset_mock',
 'return_value',
 'side_effect']
 """
2 lỗi chính tả có thể xảy ra, hãy quan sát

import requests

my_requests = requests
my_response = my_requests.get("http://www.google.com")
my_response.status_code
my_response.url

"""
200
'http://www.google.com/'
"""
4

Giả sử bạn muốn thử nghiệm phương pháp

dir(my_requests)

"""
['assert_any_call',
 'assert_called',
 'assert_called_once',
 'assert_called_once_with',
 'assert_called_with',
 'assert_has_calls',
 'assert_not_called',
 'attach_mock',
 'call_args',
 'call_args_list',
 'call_count',
 'called',
 'configure_mock',
 'method_calls',
 'mock_add_spec',
 'mock_calls',
 'reset_mock',
 'return_value',
 'side_effect']
 """
3 nhưng viết sai thành
dir(my_requests)

"""
['assert_any_call',
 'assert_called',
 'assert_called_once',
 'assert_called_once_with',
 'assert_called_with',
 'assert_has_calls',
 'assert_not_called',
 'attach_mock',
 'call_args',
 'call_args_list',
 'call_count',
 'called',
 'configure_mock',
 'method_calls',
 'mock_add_spec',
 'mock_calls',
 'reset_mock',
 'return_value',
 'side_effect']
 """
4, với chế độ giễu, cách sau vẫn hoạt động

import requests

my_requests = requests
my_response = my_requests.get("http://www.google.com")
my_response.status_code
my_response.url

"""
200
'http://www.google.com/'
"""
5

Để ngăn điều này xảy ra, chúng ta có thể sử dụng đối số

dir(my_requests)

"""
['assert_any_call',
 'assert_called',
 'assert_called_once',
 'assert_called_once_with',
 'assert_called_with',
 'assert_has_calls',
 'assert_not_called',
 'attach_mock',
 'call_args',
 'call_args_list',
 'call_count',
 'called',
 'configure_mock',
 'method_calls',
 'mock_add_spec',
 'mock_calls',
 'reset_mock',
 'return_value',
 'side_effect']
 """
5

import requests

my_requests = requests
my_response = my_requests.get("http://www.google.com")
my_response.status_code
my_response.url

"""
200
'http://www.google.com/'
"""
6

Định cấu hình giả

Đôi khi, có thể không nhập được giá trị trả về hoặc tác dụng phụ, trong trường hợp đó, chúng ta có thể sử dụng phương thức

dir(my_requests)

"""
['assert_any_call',
 'assert_called',
 'assert_called_once',
 'assert_called_once_with',
 'assert_called_with',
 'assert_has_calls',
 'assert_not_called',
 'attach_mock',
 'call_args',
 'call_args_list',
 'call_count',
 'called',
 'configure_mock',
 'method_calls',
 'mock_add_spec',
 'mock_calls',
 'reset_mock',
 'return_value',
 'side_effect']
 """
6

import requests

my_requests = requests
my_response = my_requests.get("http://www.google.com")
my_response.status_code
my_response.url

"""
200
'http://www.google.com/'
"""
7

Ngoài ra còn có các loại giả lập khác, chẳng hạn như

dir(my_requests)

"""
['assert_any_call',
 'assert_called',
 'assert_called_once',
 'assert_called_once_with',
 'assert_called_with',
 'assert_has_calls',
 'assert_not_called',
 'attach_mock',
 'call_args',
 'call_args_list',
 'call_count',
 'called',
 'configure_mock',
 'method_calls',
 'mock_add_spec',
 'mock_calls',
 'reset_mock',
 'return_value',
 'side_effect']
 """
7 và
dir(my_requests)

"""
['assert_any_call',
 'assert_called',
 'assert_called_once',
 'assert_called_once_with',
 'assert_called_with',
 'assert_has_calls',
 'assert_not_called',
 'attach_mock',
 'call_args',
 'call_args_list',
 'call_count',
 'called',
 'configure_mock',
 'method_calls',
 'mock_add_spec',
 'mock_calls',
 'reset_mock',
 'return_value',
 'side_effect']
 """
8 mới sắp ra mắt nếu bạn đang sử dụng các tính năng không đồng bộ của python

Về MagicMock, nó đi kèm với một số phương pháp bổ sung, để xem tất cả các phương pháp có sẵn,

import requests

my_requests = requests
my_response = my_requests.get("http://www.google.com")
my_response.status_code
my_response.url

"""
200
'http://www.google.com/'
"""
8

Bạn sẽ nhận thấy rằng có các phương pháp bổ sung như

dir(my_requests)

"""
['assert_any_call',
 'assert_called',
 'assert_called_once',
 'assert_called_once_with',
 'assert_called_with',
 'assert_has_calls',
 'assert_not_called',
 'attach_mock',
 'call_args',
 'call_args_list',
 'call_count',
 'called',
 'configure_mock',
 'method_calls',
 'mock_add_spec',
 'mock_calls',
 'reset_mock',
 'return_value',
 'side_effect']
 """
9 và
from unittest.mock import Mock

my_requests = Mock()
my_response = my_requests.get("http://www.google.com")
my_requests.get.assert_called() is None
my_requests.get.assert_called_with("http://www.google.com") is None

"""
True
True
"""
0

import requests

my_requests = requests
my_response = my_requests.get("http://www.google.com")
my_response.status_code
my_response.url

"""
200
'http://www.google.com/'
"""
9

Nhưng nếu bạn chỉ sử dụng phương pháp giả vani

from unittest.mock import Mock

my_requests = Mock()
my_response = my_requests.get("http://www.google.com")
my_response.status_code
my_response.url

"""


"""
0

Với tất cả các bài học ở trên, hãy nghĩ ra một số loại thử nghiệm "từ đầu đến cuối"

Chúng tôi tạo hai tập lệnh,

from unittest.mock import Mock

my_requests = Mock()
my_response = my_requests.get("http://www.google.com")
my_requests.get.assert_called() is None
my_requests.get.assert_called_with("http://www.google.com") is None

"""
True
True
"""
1 và
from unittest.mock import Mock

my_requests = Mock()
my_response = my_requests.get("http://www.google.com")
my_requests.get.assert_called() is None
my_requests.get.assert_called_with("http://www.google.com") is None

"""
True
True
"""
2

Trong

from unittest.mock import Mock

my_requests = Mock()
my_response = my_requests.get("http://www.google.com")
my_requests.get.assert_called() is None
my_requests.get.assert_called_with("http://www.google.com") is None

"""
True
True
"""
1

from unittest.mock import Mock

my_requests = Mock()
my_response = my_requests.get("http://www.google.com")
my_response.status_code
my_response.url

"""


"""
1

Hãy dành chút thời gian để hiểu điều này đang cố gắng thực hiện, chúng tôi có

  • Hàm cơ sở dữ liệu truy xuất một số thuộc tính dựa trên khóa được cung cấp (như db không có sql)
  • Một chức năng "phức tạp" mất 3 giây để chạy
  • Một số dịch vụ "bên ngoài" gửi dữ liệu cho các bên bên ngoài với một số tính năng ghi nhật ký
  • Và cuối cùng là một hàm có tính đến 3 phương thức trên thành một phương thức lớn

Giả sử chúng ta chạy

from unittest.mock import Mock

my_requests = Mock()
my_response = my_requests.get("http://www.google.com")
my_response.status_code
my_response.url

"""


"""
2

Lưu ý rằng phải mất 9 giây

kiểm tra nó

Đây là

from unittest.mock import Mock

my_requests = Mock()
my_response = my_requests.get("http://www.google.com")
my_requests.get.assert_called() is None
my_requests.get.assert_called_with("http://www.google.com") is None

"""
True
True
"""
2 của chúng tôi

from unittest.mock import Mock

my_requests = Mock()
my_response = my_requests.get("http://www.google.com")
my_response.status_code
my_response.url

"""


"""
3Hãy xem chuyện gì đang xảy ra
  • from unittest.mock import Mock
    
    my_requests = Mock()
    my_response = my_requests.get("http://www.google.com")
    my_requests.get.assert_called() is None
    my_requests.get.assert_called_with("http://www.google.com") is None
    
    """
    True
    True
    """
    5 chỉ là chức năng ban đầu mà chúng ta sẽ kiểm tra, nó sẽ in ra hai câu lệnh
    from unittest.mock import Mock
    
    my_requests = Mock()
    my_response = my_requests.get("http://www.google.com")
    my_requests.get.assert_called() is None
    my_requests.get.assert_called_with("http://www.google.com") is None
    
    """
    True
    True
    """
    6 cũng như đầu ra cuối cùng là
    from unittest.mock import Mock
    
    my_requests = Mock()
    my_response = my_requests.get("http://www.google.com")
    my_requests.get.assert_called() is None
    my_requests.get.assert_called_with("http://www.google.com") is None
    
    """
    True
    True
    """
    7 vì trước tiên chúng ta lấy giá trị của
    from unittest.mock import Mock
    
    my_requests = Mock()
    my_response = my_requests.get("http://www.google.com")
    my_requests.get.assert_called() is None
    my_requests.get.assert_called_with("http://www.google.com") is None
    
    """
    True
    True
    """
    8 là
    from unittest.mock import Mock
    
    my_requests = Mock()
    my_response = my_requests.get("http://www.google.com")
    my_requests.get.assert_called() is None
    my_requests.get.assert_called_with("http://www.google.com") is None
    
    """
    True
    True
    """
    9 và nhân với
    from unittest.mock import Mock
    
    my_requests = Mock()
    my_response = my_requests.get("http://www.google.com")
    my_response.status_code
    my_response.url
    
    """
    
    
    """
    
    10 thu được 20. sản phẩm. Sau đó,
    from unittest.mock import Mock
    
    my_requests = Mock()
    my_response = my_requests.get("http://www.google.com")
    my_response.status_code
    my_response.url
    
    """
    
    
    """
    
    11 lấy bình phương cho chúng ta
    from unittest.mock import Mock
    
    my_requests = Mock()
    my_response = my_requests.get("http://www.google.com")
    my_response.status_code
    my_response.url
    
    """
    
    
    """
    
    12
  • from unittest.mock import Mock
    
    my_requests = Mock()
    my_response = my_requests.get("http://www.google.com")
    my_response.status_code
    my_response.url
    
    """
    
    
    """
    
    13 đang kiểm tra chức năng được cho là mất 3 giây và trả về giá trị là 1, nhưng vì chúng tôi
    from unittest.mock import Mock
    
    my_requests = Mock()
    my_response = my_requests.get("http://www.google.com")
    my_response.status_code
    my_response.url
    
    """
    
    
    """
    
    14 ngay bây giờ, nên có thể trả về 123 gần như ngay lập tức

Chức năng cuối cùng hơi phức tạp (có thể?), hãy tiêu hóa nó

  • Đầu tiên, hàm
    from unittest.mock import Mock
    
    my_requests = Mock()
    my_response = my_requests.get("http://www.google.com")
    my_response.status_code
    my_response.url
    
    """
    
    
    """
    
    15 trả về cho chúng ta một giá trị là
    from unittest.mock import Mock
    
    my_requests = Mock()
    my_response = my_requests.get("http://www.google.com")
    my_response.status_code
    my_response.url
    
    """
    
    
    """
    
    10 bất kể chúng ta sử dụng
    from unittest.mock import Mock
    
    my_requests = Mock()
    my_response = my_requests.get("http://www.google.com")
    my_response.status_code
    my_response.url
    
    """
    
    
    """
    
    17 là gì
  • Thứ hai,
    from unittest.mock import Mock
    
    my_requests = Mock()
    my_response = my_requests.get("http://www.google.com")
    my_response.status_code
    my_response.url
    
    """
    
    
    """
    
    18 trả về một trình tạo, trả về
    from unittest.mock import Mock
    
    my_requests = Mock()
    my_response = my_requests.get("http://www.google.com")
    my_response.status_code
    my_response.url
    
    """
    
    
    """
    
    19 và
    from unittest.mock import Mock
    
    my_requests = Mock()
    my_response = my_requests.get("http://www.google.com")
    my_response.status_code
    my_response.url
    
    """
    
    
    """
    
    30 lần thứ hai, do đó,
    from unittest.mock import Mock
    
    my_requests = Mock()
    my_response = my_requests.get("http://www.google.com")
    my_response.status_code
    my_response.url
    
    """
    
    
    """
    
    31 là
    from unittest.mock import Mock
    
    my_requests = Mock()
    my_response = my_requests.get("http://www.google.com")
    my_response.status_code
    my_response.url
    
    """
    
    
    """
    
    19 trong khi đầu ra2 sẽ là
    from unittest.mock import Mock
    
    my_requests = Mock()
    my_response = my_requests.get("http://www.google.com")
    my_response.status_code
    my_response.url
    
    """
    
    
    """
    
    30
  • Thứ ba,
    from unittest.mock import Mock
    
    my_requests = Mock()
    my_response = my_requests.get("http://www.google.com")
    my_response.status_code
    my_response.url
    
    """
    
    
    """
    
    34 đang được vá bằng một đối tượng
    type(my_response)
    
    """
    unittest.mock.Mock
    """
    1

Bây giờ, chúng tôi chạy thử nghiệm

from unittest.mock import Mock

my_requests = Mock()
my_response = my_requests.get("http://www.google.com")
my_response.status_code
my_response.url

"""


"""
4
  • from unittest.mock import Mock
    
    my_requests = Mock()
    my_response = my_requests.get("http://www.google.com")
    my_response.status_code
    my_response.url
    
    """
    
    
    """
    
    36 hiển thị 3 bài kiểm tra chậm nhất
  • from unittest.mock import Mock
    
    my_requests = Mock()
    my_response = my_requests.get("http://www.google.com")
    my_response.status_code
    my_response.url
    
    """
    
    
    """
    
    37 cho dài dòng
  • from unittest.mock import Mock
    
    my_requests = Mock()
    my_response = my_requests.get("http://www.google.com")
    my_response.status_code
    my_response.url
    
    """
    
    
    """
    
    38 để hiển thị nhật ký

đầu ra

from unittest.mock import Mock

my_requests = Mock()
my_response = my_requests.get("http://www.google.com")
my_response.status_code
my_response.url

"""


"""
5

Nếu chúng tôi loại bỏ

from unittest.mock import Mock

my_requests = Mock()
my_response = my_requests.get("http://www.google.com")
my_requests.get.assert_called() is None
my_requests.get.assert_called_with("http://www.google.com") is None

"""
True
True
"""
5 khỏi mã của mình, đây là kết quả

from unittest.mock import Mock

my_requests = Mock()
my_response = my_requests.get("http://www.google.com")
my_response.status_code
my_response.url

"""


"""
6

Lưu ý rằng trong

from unittest.mock import Mock

my_requests = Mock()
my_response = my_requests.get("http://www.google.com")
my_response.status_code
my_response.url

"""


"""
34 không có nhật ký
from unittest.mock import Mock

my_requests = Mock()
my_response = my_requests.get("http://www.google.com")
my_requests.get.assert_called() is None
my_requests.get.assert_called_with("http://www.google.com") is None

"""
True
True
"""
6 nào được ghi lại và cơ sở dữ liệu không tác động "trực tiếp" đến nó, cô lập các phần phụ thuộc của chúng tôi. Ngoài ra, chúng tôi cũng "bỏ qua" các chức năng phức tạp của chúng tôi