Hướng dẫn what is side_ effect in mock python? - hiệu ứng side_ trong python giả là gì?

Mới trong phiên bản 3.3.

Sử dụng Mock¶

Phương pháp vá lỗi

Sử dụng phổ biến cho các đối tượng

>>> expected = [call.method(), call.attribute.method(10, x=53)]
>>> mock.mock_calls == expected
True
6 bao gồm:

  • Phương pháp vá lỗi

  • Phương thức ghi lại các cuộc gọi trên các đối tượng

Bạn có thể muốn thay thế một phương thức trên một đối tượng để kiểm tra xem nó được gọi bằng các đối số chính xác bởi một phần khác của hệ thống:

>>> real = SomeClass()
>>> real.method = MagicMock(name='method')
>>> real.method(3, 4, 5, key='value')
<MagicMock name='method()' id='...'>

Khi giả của chúng tôi đã được sử dụng (

>>> expected = [call.method(), call.attribute.method(10, x=53)]
>>> mock.mock_calls == expected
True
7 trong ví dụ này), nó có các phương thức và thuộc tính cho phép bạn đưa ra các xác nhận về cách sử dụng nó.

Ghi chú

Trong hầu hết các ví dụ này, các lớp

>>> expected = [call.method(), call.attribute.method(10, x=53)]
>>> mock.mock_calls == expected
True
6 và
>>> expected = [call.method(), call.attribute.method(10, x=53)]
>>> mock.mock_calls == expected
True
9 có thể hoán đổi cho nhau. Vì
>>> expected = [call.method(), call.attribute.method(10, x=53)]
>>> mock.mock_calls == expected
True
9 là lớp có khả năng hơn, nó tạo ra một lớp hợp lý được sử dụng theo mặc định.

Khi giả đã được gọi là thuộc tính

>>> m = Mock()
>>> m.factory(important=True).deliver()
<Mock name='mock.factory().deliver()' id='...'>
>>> m.mock_calls[-1] == call.factory(important=False).deliver()
True
1 của nó được đặt thành
>>> m = Mock()
>>> m.factory(important=True).deliver()
<Mock name='mock.factory().deliver()' id='...'>
>>> m.mock_calls[-1] == call.factory(important=False).deliver()
True
2. Quan trọng hơn, chúng ta có thể sử dụng phương pháp
>>> m = Mock()
>>> m.factory(important=True).deliver()
<Mock name='mock.factory().deliver()' id='...'>
>>> m.mock_calls[-1] == call.factory(important=False).deliver()
True
3 hoặc
>>> m = Mock()
>>> m.factory(important=True).deliver()
<Mock name='mock.factory().deliver()' id='...'>
>>> m.mock_calls[-1] == call.factory(important=False).deliver()
True
4 để kiểm tra xem nó có được gọi với các đối số chính xác không.

Ví dụ này kiểm tra rằng việc gọi

>>> m = Mock()
>>> m.factory(important=True).deliver()
<Mock name='mock.factory().deliver()' id='...'>
>>> m.mock_calls[-1] == call.factory(important=False).deliver()
True
5 dẫn đến một cuộc gọi đến phương thức
>>> m = Mock()
>>> m.factory(important=True).deliver()
<Mock name='mock.factory().deliver()' id='...'>
>>> m.mock_calls[-1] == call.factory(important=False).deliver()
True
6:

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)

Chế giễu phương thức gọi trên một đối tượng

Trong ví dụ cuối cùng, chúng tôi đã vá một phương thức trực tiếp trên một đối tượng để kiểm tra xem nó có được gọi chính xác không. Một trường hợp sử dụng phổ biến khác là chuyển một đối tượng vào một phương thức (hoặc một phần của hệ thống được kiểm tra) và sau đó kiểm tra xem nó có được sử dụng đúng cách không.

>>> m = Mock()
>>> m.factory(important=True).deliver()
<Mock name='mock.factory().deliver()' id='...'>
>>> m.mock_calls[-1] == call.factory(important=False).deliver()
True
7 đơn giản dưới đây có phương pháp
>>> m = Mock()
>>> m.factory(important=True).deliver()
<Mock name='mock.factory().deliver()' id='...'>
>>> m.mock_calls[-1] == call.factory(important=False).deliver()
True
8. Nếu nó được gọi với một đối tượng thì nó sẽ gọi
>>> m = Mock()
>>> m.factory(important=True).deliver()
<Mock name='mock.factory().deliver()' id='...'>
>>> m.mock_calls[-1] == call.factory(important=False).deliver()
True
9 trên nó.

>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...

Vì vậy, để kiểm tra nó, chúng ta cần truyền trong một đối tượng bằng phương pháp

>>> m = Mock()
>>> m.factory(important=True).deliver()
<Mock name='mock.factory().deliver()' id='...'>
>>> m.mock_calls[-1] == call.factory(important=False).deliver()
True
9 và kiểm tra xem nó có được gọi chính xác không.

>>> real = ProductionClass()
>>> mock = Mock()
>>> real.closer(mock)
>>> mock.close.assert_called_with()

Chúng tôi không phải làm bất kỳ công việc nào để cung cấp phương thức ’đóng trên giả của chúng tôi. Truy cập gần tạo ra nó. Vì vậy, nếu ’Đóng, đã được gọi thì việc truy cập nó trong bài kiểm tra sẽ tạo ra nó, nhưng

>>> m = Mock()
>>> m.factory(important=True).deliver()
<Mock name='mock.factory().deliver()' id='...'>
>>> m.mock_calls[-1] == call.factory(important=False).deliver()
True
3 sẽ làm tăng một ngoại lệ thất bại.

Các lớp học chế giễu

Một trường hợp sử dụng phổ biến là chế giễu các lớp được khởi tạo bởi mã của bạn đang được kiểm tra. Khi bạn vá một lớp, thì lớp đó được thay thế bằng một giả. Các thể hiện được tạo bằng cách gọi lớp. Điều này có nghĩa là bạn truy cập vào phiên bản Mock Mock bằng cách xem xét giá trị trả về của lớp bị chế giễu.

Trong ví dụ dưới đây, chúng tôi có hàm

>>> mock = Mock()
>>> mock.return_value = 3
>>> mock()
3
2 khởi tạo
>>> mock = Mock()
>>> mock.return_value = 3
>>> mock()
3
3 và gọi một phương thức trên đó. Cuộc gọi đến
>>> mock = Mock()
>>> mock.return_value = 3
>>> mock()
3
4 thay thế lớp
>>> mock = Mock()
>>> mock.return_value = 3
>>> mock()
3
3 bằng một giả. Ví dụ
>>> mock = Mock()
>>> mock.return_value = 3
>>> mock()
3
3 là kết quả của việc gọi giả, vì vậy nó được cấu hình bằng cách sửa đổi giả
>>> mock = Mock()
>>> mock.return_value = 3
>>> mock()
3
7.

>>> def some_function():
...     instance = module.Foo()
...     return instance.method()
...
>>> with patch('module.Foo') as mock:
...     instance = mock.return_value
...     instance.method.return_value = 'the result'
...     result = some_function()
...     assert result == 'the result'

Đặt tên cho giả của bạn

Nó có thể hữu ích để đặt tên cho Mocks của bạn. Tên được hiển thị trong repr of the Mock và có thể hữu ích khi giả xuất hiện trong các thông báo thất bại thử nghiệm. Tên cũng được truyền đến các thuộc tính hoặc phương thức của giả:

>>> mock = MagicMock(name='foo')
>>> mock
<MagicMock name='foo' id='...'>
>>> mock.method
<MagicMock name='foo.method' id='...'>

Theo dõi tất cả các cuộc gọi

Thường thì bạn muốn theo dõi nhiều hơn một cuộc gọi đến một phương thức. Thuộc tính

>>> mock = Mock()
>>> mock.return_value = 3
>>> mock()
3
8 ghi lại tất cả các cuộc gọi đến các thuộc tính con của giả - và cả con cái của họ.

>>> mock = MagicMock()
>>> mock.method()
<MagicMock name='mock.method()' id='...'>
>>> mock.attribute.method(10, x=53)
<MagicMock name='mock.attribute.method()' id='...'>
>>> mock.mock_calls
[call.method(), call.attribute.method(10, x=53)]

Nếu bạn đưa ra một khẳng định về

>>> mock = Mock()
>>> mock.return_value = 3
>>> mock()
3
8 và bất kỳ phương pháp bất ngờ nào đã được gọi, thì khẳng định sẽ thất bại. Điều này rất hữu ích vì cũng như khẳng định rằng các cuộc gọi bạn dự kiến ​​đã được thực hiện, bạn cũng đang kiểm tra xem chúng đã được thực hiện đúng thứ tự và không có cuộc gọi bổ sung nào:

Bạn sử dụng đối tượng

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
00 để xây dựng danh sách để so sánh với
>>> mock = Mock()
>>> mock.return_value = 3
>>> mock()
3
8:

>>> expected = [call.method(), call.attribute.method(10, x=53)]
>>> mock.mock_calls == expected
True

Tuy nhiên, các tham số cho các cuộc gọi mà giả trả lại không được ghi lại, điều đó có nghĩa là không thể theo dõi các cuộc gọi lồng nhau trong đó các tham số được sử dụng để tạo tổ tiên là quan trọng:

________số 8

Đặt giá trị trả về và các thuộc tính

Đặt các giá trị trả về trên một đối tượng giả là dễ dàng:

>>> mock = Mock()
>>> mock.return_value = 3
>>> mock()
3

Tất nhiên bạn có thể làm tương tự cho các phương thức trên chế độ giả:

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
0

Giá trị trả về cũng có thể được đặt trong hàm tạo:

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
1

Nếu bạn cần cài đặt thuộc tính trên giả, chỉ cần làm điều đó:

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
2

Đôi khi bạn muốn chế giễu một tình huống phức tạp hơn, như ví dụ

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
02. Nếu chúng tôi muốn cuộc gọi này trả lại một danh sách, thì chúng tôi phải định cấu hình kết quả của cuộc gọi lồng nhau.

Chúng ta có thể sử dụng

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
00 để xây dựng tập hợp các cuộc gọi trong một cuộc gọi xích trực tiếp như thế này để dễ dàng khẳng định sau đó:

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
3

Đó là cuộc gọi đến

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
04 biến đối tượng cuộc gọi của chúng tôi thành một danh sách các cuộc gọi đại diện cho các cuộc gọi xích.

Tăng ngoại lệ với Mocks¶

Một thuộc tính hữu ích là

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
05. Nếu bạn đặt cái này thành một lớp hoặc thể hiện ngoại lệ thì ngoại lệ sẽ được nâng lên khi giả được gọi.

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
4

Chức năng tác dụng phụ và Iterables¶

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
05 cũng có thể được đặt thành một chức năng hoặc một điều không thể điều chỉnh được. Trường hợp sử dụng cho
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
05 như một điều có thể là nơi mà giả của bạn sẽ được gọi nhiều lần và bạn muốn mỗi cuộc gọi trả về một giá trị khác nhau. Khi bạn đặt
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
05 thành một cuộc gọi có thể lặp lại, việc giả sẽ trả về giá trị tiếp theo từ điều đáng tin cậy:

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
5

Đối với các trường hợp sử dụng nâng cao hơn, như thay đổi động, các giá trị trả về tùy thuộc vào những gì giả được gọi với,

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
05 có thể là một hàm. Hàm sẽ được gọi với các đối số tương tự như giả. Bất kể hàm nào trả về là những gì cuộc gọi trả về:

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
6

Chế giễu máy lặp không đồng bộ

Kể từ Python 3.8,

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
10 và
>>> expected = [call.method(), call.attribute.method(10, x=53)]
>>> mock.mock_calls == expected
True
9 có hỗ trợ để chế giễu các trình lặp không đồng bộ thông qua
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
12. Thuộc tính
>>> mock = Mock()
>>> mock.return_value = 3
>>> mock()
3
7 của
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
12 có thể được sử dụng để đặt các giá trị trả về được sử dụng để lặp.Asynchronous Iterators through
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
12. The
>>> mock = Mock()
>>> mock.return_value = 3
>>> mock()
3
7 attribute of
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
12 can be used to set the return values to be used for iteration.

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
7

Chế tạo người quản lý bối cảnh không đồng bộ

Kể từ Python 3.8,

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
10 và
>>> expected = [call.method(), call.attribute.method(10, x=53)]
>>> mock.mock_calls == expected
True
9 có hỗ trợ để chế giễu các nhà quản lý bối cảnh không đồng bộ thông qua
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
17 và
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
18. Theo mặc định,
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
17 và
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
18 là các trường hợp
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
10 trả về hàm async.Asynchronous Context Managers through
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
17 and
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
18. By default,
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
17 and
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
18 are
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
10 instances that return an async function.

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
8

Tạo một sự giả từ một đối tượng hiện có

Một vấn đề với việc sử dụng quá mức việc chế giễu là nó kết hợp các bài kiểm tra của bạn để thực hiện giả của bạn hơn là mã thực của bạn. Giả sử bạn có một lớp thực hiện

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
22. Trong một bài kiểm tra cho một lớp khác, bạn cung cấp một chế độ giả của đối tượng này cũng cung cấp
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
22. Nếu sau này bạn tái cấu trúc lớp đầu tiên, do đó nó không còn có
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
22 - thì các bài kiểm tra của bạn sẽ tiếp tục vượt qua mặc dù mã của bạn đã bị hỏng!

>>> expected = [call.method(), call.attribute.method(10, x=53)]
>>> mock.mock_calls == expected
True
6 cho phép bạn cung cấp một đối tượng như một đặc điểm kỹ thuật cho giả, sử dụng đối số từ khóa Spec. Truy cập các phương thức / thuộc tính trên giả don don tồn tại trên đối tượng đặc tả của bạn sẽ ngay lập tức gây ra lỗi thuộc tính. Nếu bạn thay đổi việc thực hiện đặc tả của mình, thì các bài kiểm tra sử dụng lớp đó sẽ bắt đầu thất bại ngay lập tức mà không cần bạn phải khởi tạo lớp trong các bài kiểm tra đó.

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
9

Sử dụng một đặc điểm kỹ thuật cũng cho phép khớp thông minh hơn các cuộc gọi được thực hiện với giả, bất kể một số tham số được truyền dưới dạng đối số vị trí hay được đặt tên:

>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
0

Nếu bạn muốn kết hợp thông minh hơn này cũng hoạt động với các cuộc gọi phương thức trên giả, bạn có thể sử dụng tự động.auto-speccing.

Nếu bạn muốn một hình thức đặc tả mạnh mẽ hơn để ngăn chặn việc cài đặt các thuộc tính tùy ý cũng như nhận được chúng thì bạn có thể sử dụng spec_set thay vì spec.

Người trang trí bản vá

Ghi chú

Với

>>> mock = Mock()
>>> mock.return_value = 3
>>> mock()
3
4, vấn đề là bạn vá các đối tượng trong không gian tên nơi chúng được nhìn lên. Điều này thường đơn giản, nhưng đối với một hướng dẫn nhanh, hãy đọc nơi để vá.where to patch.

Một nhu cầu phổ biến trong các thử nghiệm là vá một thuộc tính lớp hoặc thuộc tính mô -đun, ví dụ như vá lỗi hoặc vá một lớp trong một mô -đun để kiểm tra rằng nó được khởi tạo. Các mô -đun và các lớp có hiệu quả toàn cầu, vì vậy việc vá lỗi trên chúng phải được hoàn tác sau khi kiểm tra hoặc bản vá sẽ tồn tại trong các xét nghiệm khác và gây khó chẩn đoán các vấn đề.

Mock cung cấp ba nhà trang trí thuận tiện cho việc này:

>>> mock = Mock()
>>> mock.return_value = 3
>>> mock()
3
4,
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
28 và
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
29.
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
30 có một chuỗi duy nhất, của mẫu
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
31 để chỉ định thuộc tính bạn đang vá. Nó cũng tùy chọn lấy một giá trị mà bạn muốn thuộc tính (hoặc lớp hoặc bất cứ điều gì) được thay thế bằng. ‘Patch.Object, lấy một đối tượng và tên của thuộc tính bạn muốn được vá, cộng với giá trị tùy chọn để vá nó.

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
32:

>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
1

Nếu bạn đang vá một mô -đun (bao gồm

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
33) thì hãy sử dụng
>>> mock = Mock()
>>> mock.return_value = 3
>>> mock()
3
4 thay vì
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
28:

>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
2

Tên mô -đun có thể được ‘chấm, ở dạng

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
36 nếu cần:

>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
3

Một mô hình đẹp là thực sự trang trí các phương pháp kiểm tra:

>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
4

Nếu bạn muốn vá bằng một giả, bạn có thể sử dụng

>>> mock = Mock()
>>> mock.return_value = 3
>>> mock()
3
4 chỉ với một đối số (hoặc
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
28 với hai đối số). Mock sẽ được tạo cho bạn và được chuyển vào hàm / phương thức kiểm tra:

>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
5

Bạn có thể xếp chồng lên nhiều bộ trang trí bản vá bằng cách sử dụng mẫu này:

>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
6

Khi bạn làm tổ trang trí, các chế độ giả được chuyển vào chức năng được trang trí theo cùng thứ tự chúng được áp dụng (thứ tự python bình thường mà các nhà trang trí được áp dụng). Điều này có nghĩa là từ dưới lên, vì vậy trong ví dụ trên giả cho

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
39 được thông qua đầu tiên.

Ngoài ra còn có

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
29 để thiết lập các giá trị trong một từ điển chỉ trong một phạm vi và khôi phục từ điển về trạng thái ban đầu của nó khi thử nghiệm kết thúc:

>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
7

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
30,
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
32 và
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
43 đều có thể được sử dụng làm người quản lý ngữ cảnh.

Khi bạn sử dụng

>>> mock = Mock()
>>> mock.return_value = 3
>>> mock()
3
4 để tạo một chế độ giả cho bạn, bạn có thể nhận được một tham chiếu đến giả sử dụng hình thức As As As của câu lệnh với câu lệnh:

>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
8

Thay thế

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
30,
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
32 và
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
43 có thể được sử dụng làm người trang trí lớp. Khi được sử dụng theo cách này, nó giống như áp dụng riêng bộ trang trí cho mọi phương pháp có tên bắt đầu bằng cách kiểm tra.

Ví dụ thêm

Dưới đây là một số ví dụ khác cho một số kịch bản nâng cao hơn một chút.

Chế tạo các cuộc gọi xích

Các cuộc gọi xích thực sự thực sự đơn giản với giả một khi bạn hiểu thuộc tính

>>> mock = Mock()
>>> mock.return_value = 3
>>> mock()
3
7. Khi một giả được gọi cho lần đầu tiên, hoặc bạn lấy
>>> mock = Mock()
>>> mock.return_value = 3
>>> mock()
3
7 của nó trước khi nó được gọi, một
>>> expected = [call.method(), call.attribute.method(10, x=53)]
>>> mock.mock_calls == expected
True
6 mới được tạo ra.

Điều này có nghĩa là bạn có thể thấy cách đối tượng được trả lại từ một cuộc gọi cho một đối tượng bị chế giễu đã được sử dụng bằng cách thẩm vấn giả

>>> mock = Mock()
>>> mock.return_value = 3
>>> mock()
3
7:

>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
9

Từ đây, đó là một bước đơn giản để định cấu hình và sau đó đưa ra các xác nhận về các cuộc gọi bị xích. Tất nhiên, một giải pháp khác là viết mã của bạn theo cách có thể kiểm tra hơn ở nơi đầu tiên

Vì vậy, giả sử chúng ta có một số mã trông hơi như sau:

>>> real = ProductionClass()
>>> mock = Mock()
>>> real.closer(mock)
>>> mock.close.assert_called_with()
0

Giả sử rằng

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
52 đã được kiểm tra tốt, làm thế nào để chúng ta kiểm tra
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
53? Cụ thể, chúng tôi muốn kiểm tra rằng phần mã
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
54 sử dụng đối tượng phản hồi theo cách chính xác.

Vì chuỗi các cuộc gọi này được thực hiện từ một thuộc tính thể hiện, chúng tôi có thể vá cho thuộc tính

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
55 trên một thể hiện
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
56. Trong trường hợp cụ thể này, chúng tôi chỉ quan tâm đến giá trị trả lại từ cuộc gọi cuối cùng đến
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
57 vì vậy chúng tôi không có nhiều cấu hình để làm. Hãy để giả sử đối tượng mà nó trả về là ‘giống như tệp, vì vậy chúng tôi sẽ đảm bảo rằng đối tượng phản hồi của chúng tôi sử dụng
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
58 tích hợp làm
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
59.

Để làm điều này, chúng tôi tạo một thể hiện giả khi phụ trợ giả của chúng tôi và tạo một đối tượng phản hồi giả cho nó. Để đặt phản hồi làm giá trị trả về cho

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
57 cuối cùng, chúng tôi có thể làm điều này:

>>> real = ProductionClass()
>>> mock = Mock()
>>> real.closer(mock)
>>> mock.close.assert_called_with()
1

Chúng ta có thể làm điều đó theo một cách đẹp hơn một chút bằng cách sử dụng phương thức

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
61 để đặt trực tiếp giá trị trả về cho chúng tôi:

>>> real = ProductionClass()
>>> mock = Mock()
>>> real.closer(mock)
>>> mock.close.assert_called_with()
2

Với những điều này, chúng tôi đã vá bản vá lỗi của người Hồi giáo tại chỗ và có thể thực hiện cuộc gọi thực sự:

>>> real = ProductionClass()
>>> mock = Mock()
>>> real.closer(mock)
>>> mock.close.assert_called_with()
3

Sử dụng

>>> mock = Mock()
>>> mock.return_value = 3
>>> mock()
3
8, chúng tôi có thể kiểm tra cuộc gọi chuỗi với một khẳng định. Một cuộc gọi có chuỗi là một số cuộc gọi trong một dòng mã, vì vậy sẽ có một số mục trong
>>> mock = Mock()
>>> mock.return_value = 3
>>> mock()
3
8. Chúng tôi có thể sử dụng
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
64 để tạo danh sách các cuộc gọi này cho chúng tôi:

>>> real = ProductionClass()
>>> mock = Mock()
>>> real.closer(mock)
>>> mock.close.assert_called_with()
4

Chế giễu một phần

Trong một số thử nghiệm, tôi muốn chế giễu cuộc gọi đến

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
65 để trả về một ngày đã biết, nhưng tôi đã không muốn ngăn mã được kiểm tra tạo các đối tượng ngày mới. Thật không may,
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
66 được viết bằng C, và vì vậy tôi không thể chỉ có một phương pháp
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
67 tĩnh.

Tôi đã tìm thấy một cách đơn giản để làm điều này liên quan đến việc kết thúc hiệu quả lớp ngày bằng một chế độ giả, nhưng chuyển qua các cuộc gọi đến nhà xây dựng cho lớp thực (và trả lại các trường hợp thực).

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
68 được sử dụng ở đây để chế giễu lớp
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
69 trong mô -đun được thử nghiệm. Thuộc tính ____105 trên lớp ngày giả sau đó được đặt thành hàm Lambda trả về một ngày thực. Khi lớp ngày giả được gọi là một ngày thực tế sẽ được xây dựng và trả lại bởi
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
05.

>>> real = ProductionClass()
>>> mock = Mock()
>>> real.closer(mock)
>>> mock.close.assert_called_with()
5

Lưu ý rằng chúng tôi không có bản vá

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
66 trên toàn cầu, chúng tôi vá
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
69 trong mô -đun sử dụng nó. Xem nơi để vá.where to patch.

Khi

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
67 được gọi là một ngày đã biết được trả về, nhưng các cuộc gọi đến hàm tạo
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
75 vẫn trả về ngày bình thường. Không có điều này, bạn có thể thấy mình phải tính toán kết quả dự kiến ​​bằng cách sử dụng chính xác cùng một thuật toán với mã được thử nghiệm, đây là một thử nghiệm cổ điển chống lại mẫu.

Các cuộc gọi đến Trình xây dựng ngày được ghi lại trong các thuộc tính

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
76 (
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
77 và bạn bè) cũng có thể hữu ích cho các bài kiểm tra của bạn.

Một cách khác để đối phó với ngày chế giễu, hoặc các lớp xây dựng khác, được thảo luận trong mục blog này.

Chế giễu phương thức máy phát điện

Trình tạo Python là một hàm hoặc phương thức sử dụng câu lệnh

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
78 để trả về một loạt các giá trị khi lặp lại trên 1.

Một phương thức / hàm máy phát được gọi để trả về đối tượng Trình tạo. Nó là đối tượng máy phát mà sau đó được lặp lại. Phương pháp giao thức để lặp là

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
79, vì vậy chúng ta có thể chế giễu điều này bằng cách sử dụng
>>> expected = [call.method(), call.attribute.method(10, x=53)]
>>> mock.mock_calls == expected
True
9.

Ở đây, một lớp ví dụ với một phương thức IT ITER được triển khai như một trình tạo:

>>> real = ProductionClass()
>>> mock = Mock()
>>> real.closer(mock)
>>> mock.close.assert_called_with()
6

Làm thế nào chúng ta sẽ chế giễu lớp này, và đặc biệt là phương pháp IT ITER của nó?

Để định cấu hình các giá trị được trả về từ lần lặp (ẩn trong cuộc gọi đến

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
81), chúng ta cần cấu hình đối tượng được trả về bởi cuộc gọi đến
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
82.

>>> real = ProductionClass()
>>> mock = Mock()
>>> real.closer(mock)
>>> mock.close.assert_called_with()
7

1

Ngoài ra còn có các biểu thức máy phát và sử dụng các máy phát điện nâng cao hơn, nhưng chúng tôi không quan tâm đến chúng ở đây. Một giới thiệu rất tốt về máy phát điện và chúng mạnh mẽ như thế nào: thủ thuật máy phát điện cho các lập trình viên hệ thống.

Áp dụng cùng một bản vá cho mọi phương pháp kiểm tra

Nếu bạn muốn một số bản vá tại chỗ cho nhiều phương pháp thử nghiệm, cách rõ ràng là áp dụng các bộ trang trí bản vá cho mọi phương pháp. Điều này có thể cảm thấy như sự lặp lại không cần thiết. Thay vào đó, bạn có thể sử dụng

>>> mock = Mock()
>>> mock.return_value = 3
>>> mock()
3
4 (trong tất cả các hình thức khác nhau của nó) như một người trang trí lớp. Điều này áp dụng các bản vá cho tất cả các phương pháp kiểm tra trên lớp. Một phương thức kiểm tra được xác định bằng các phương thức có tên bắt đầu bằng
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
84:

>>> real = ProductionClass()
>>> mock = Mock()
>>> real.closer(mock)
>>> mock.close.assert_called_with()
8

Một cách khác để quản lý các bản vá là sử dụng các phương thức vá: Bắt đầu và dừng lại. Chúng cho phép bạn di chuyển các bản vá vào các phương thức

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
85 và
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
86 của bạn.patch methods: start and stop. These allow you to move the patching into your
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
85 and
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
86 methods.

>>> real = ProductionClass()
>>> mock = Mock()
>>> real.closer(mock)
>>> mock.close.assert_called_with()
9

Nếu bạn sử dụng kỹ thuật này, bạn phải đảm bảo rằng việc vá lỗi được hoàn tác bằng cách gọi

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
87. Điều này có thể khó khăn hơn bạn nghĩ, bởi vì nếu một ngoại lệ được nêu ra trong thiết lập thì Teardown không được gọi.
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
88 làm cho điều này dễ dàng hơn:

>>> def some_function():
...     instance = module.Foo()
...     return instance.method()
...
>>> with patch('module.Foo') as mock:
...     instance = mock.return_value
...     instance.method.return_value = 'the result'
...     result = some_function()
...     assert result == 'the result'
0

Chế giễu các phương pháp không bị ràng buộc

Trong khi viết các bài kiểm tra ngày hôm nay, tôi cần phải vá một phương thức không liên kết (vá phương thức trên lớp thay vì trên ví dụ). Tôi cần phải được truyền vào như một đối số đầu tiên bởi vì tôi muốn đưa ra những khẳng định về những đối tượng nào đang gọi phương thức cụ thể này. Vấn đề là bạn không thể vá bằng một chế độ giả cho việc này, bởi vì nếu bạn thay thế một phương thức không liên kết bằng một chế độ giả, nó không trở thành một phương thức ràng buộc khi được tìm nạp từ trường hợp, và vì vậy nó không được tự truyền vào. Giải pháp thay thế là để vá phương pháp không liên kết với một hàm thực thay thế. Bộ trang trí

>>> mock = Mock()
>>> mock.return_value = 3
>>> mock()
3
4 làm cho nó rất đơn giản để vá các phương thức với một chế độ giả phải tạo ra một chức năng thực sự trở thành một mối phiền toái.

Nếu bạn vượt qua

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
90 để vá thì nó thực hiện bản vá với một đối tượng chức năng thực. Đối tượng chức năng này có chữ ký tương tự như cái mà nó đang thay thế, nhưng ủy quyền cho một chế giễu dưới mui xe. Bạn vẫn nhận được tự động tạo tự động theo cách tương tự như trước đây. Mặc dù vậy, điều đó có nghĩa là nếu bạn sử dụng nó để vá một phương thức không liên kết trên một lớp, hàm bị chế giễu sẽ được biến thành một phương thức ràng buộc nếu nó được tìm nạp từ một thể hiện. Nó sẽ có
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
91 được thông qua như là đối số đầu tiên, đó chính xác là những gì tôi muốn:

>>> def some_function():
...     instance = module.Foo()
...     return instance.method()
...
>>> with patch('module.Foo') as mock:
...     instance = mock.return_value
...     instance.method.return_value = 'the result'
...     result = some_function()
...     assert result == 'the result'
1

Nếu chúng ta không sử dụng

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
90 thì phương pháp không liên kết được vá ra với một thể hiện giả thay thế, và được gọi với
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
91.

Kiểm tra nhiều cuộc gọi với Mock¶

Mock có một API đẹp để đưa ra các xác nhận về cách sử dụng các đối tượng giả của bạn.

>>> def some_function():
...     instance = module.Foo()
...     return instance.method()
...
>>> with patch('module.Foo') as mock:
...     instance = mock.return_value
...     instance.method.return_value = 'the result'
...     result = some_function()
...     assert result == 'the result'
2

Nếu giả của bạn chỉ được gọi là một khi bạn có thể sử dụng phương thức

>>> m = Mock()
>>> m.factory(important=True).deliver()
<Mock name='mock.factory().deliver()' id='...'>
>>> m.mock_calls[-1] == call.factory(important=False).deliver()
True
4 cũng khẳng định rằng
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
77 là một.

>>> def some_function():
...     instance = module.Foo()
...     return instance.method()
...
>>> with patch('module.Foo') as mock:
...     instance = mock.return_value
...     instance.method.return_value = 'the result'
...     result = some_function()
...     assert result == 'the result'
3

Cả

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
96 và
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
97 đều đưa ra các xác nhận về cuộc gọi gần đây nhất. Nếu giả của bạn sẽ được gọi là nhiều lần và bạn muốn đưa ra các xác nhận về tất cả những cuộc gọi đó bạn có thể sử dụng
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
98:

>>> def some_function():
...     instance = module.Foo()
...     return instance.method()
...
>>> with patch('module.Foo') as mock:
...     instance = mock.return_value
...     instance.method.return_value = 'the result'
...     result = some_function()
...     assert result == 'the result'
4

Trình trợ giúp

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
00 giúp dễ dàng đưa ra các xác nhận về các cuộc gọi này. Bạn có thể xây dựng một danh sách các cuộc gọi mong đợi và so sánh nó với
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
98. Điều này trông rất giống với repr của
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
98:

>>> def some_function():
...     instance = module.Foo()
...     return instance.method()
...
>>> with patch('module.Foo') as mock:
...     instance = mock.return_value
...     instance.method.return_value = 'the result'
...     result = some_function()
...     assert result == 'the result'
5

Đối phó với các đối số có thể thay đổi

Một tình huống khác là rất hiếm, nhưng có thể cắn bạn, là khi giả của bạn được gọi với các đối số có thể thay đổi.

>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
02 và
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
98 Lưu trữ tham chiếu đến các đối số. Nếu các đối số bị đột biến bởi mã được kiểm tra thì bạn không còn có thể đưa ra các xác nhận về những giá trị là gì khi giả được gọi.

Ở đây, một số mã ví dụ hiển thị vấn đề. Hãy tưởng tượng các chức năng sau được xác định trong ‘mymodule,:

>>> def some_function():
...     instance = module.Foo()
...     return instance.method()
...
>>> with patch('module.Foo') as mock:
...     instance = mock.return_value
...     instance.method.return_value = 'the result'
...     result = some_function()
...     assert result == 'the result'
6

Khi chúng tôi cố gắng kiểm tra rằng

>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
04 gọi
>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
05 với đối số chính xác, hãy xem những gì xảy ra:

>>> def some_function():
...     instance = module.Foo()
...     return instance.method()
...
>>> with patch('module.Foo') as mock:
...     instance = mock.return_value
...     instance.method.return_value = 'the result'
...     result = some_function()
...     assert result == 'the result'
7

Một khả năng sẽ là để Mock sao chép các đối số bạn truyền vào. Điều này sau đó có thể gây ra vấn đề nếu bạn thực hiện các khẳng định dựa vào nhận dạng đối tượng cho sự bình đẳng.

Ở đây, một giải pháp sử dụng chức năng

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
05. Nếu bạn cung cấp chức năng
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
05 cho một chế độ giả thì
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
05 sẽ được gọi với cùng một đối số như giả. Điều này cho chúng tôi một cơ hội để sao chép các đối số và lưu trữ chúng để xác nhận sau này. Trong ví dụ này, tôi đã sử dụng một chế độ giả khác để lưu trữ các đối số để tôi có thể sử dụng các phương thức giả để thực hiện khẳng định. Một lần nữa, một chức năng trợ giúp thiết lập điều này cho tôi.

>>> def some_function():
...     instance = module.Foo()
...     return instance.method()
...
>>> with patch('module.Foo') as mock:
...     instance = mock.return_value
...     instance.method.return_value = 'the result'
...     result = some_function()
...     assert result == 'the result'
8

>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
09 được gọi với giả sẽ được gọi. Nó trả lại một giả mới mà chúng tôi thực hiện khẳng định. Hàm
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
05 tạo một bản sao của ARG và gọi
>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
11 của chúng tôi với bản sao.

Ghi chú

Nếu giả của bạn sẽ chỉ được sử dụng một khi có một cách dễ dàng hơn để kiểm tra các đối số tại điểm chúng được gọi. Bạn chỉ có thể thực hiện kiểm tra bên trong hàm

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
05.

>>> def some_function():
...     instance = module.Foo()
...     return instance.method()
...
>>> with patch('module.Foo') as mock:
...     instance = mock.return_value
...     instance.method.return_value = 'the result'
...     result = some_function()
...     assert result == 'the result'
9

Một cách tiếp cận khác là tạo ra một lớp con của

>>> expected = [call.method(), call.attribute.method(10, x=53)]
>>> mock.mock_calls == expected
True
6 hoặc
>>> expected = [call.method(), call.attribute.method(10, x=53)]
>>> mock.mock_calls == expected
True
9 sao chép (sử dụng
>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
15) các đối số. Ở đây, một ví dụ thực hiện:

>>> mock = MagicMock(name='foo')
>>> mock
<MagicMock name='foo' id='...'>
>>> mock.method
<MagicMock name='foo.method' id='...'>
0

Khi bạn phân lớp

>>> expected = [call.method(), call.attribute.method(10, x=53)]
>>> mock.mock_calls == expected
True
6 hoặc
>>> expected = [call.method(), call.attribute.method(10, x=53)]
>>> mock.mock_calls == expected
True
9 tất cả các thuộc tính được tạo động và
>>> mock = Mock()
>>> mock.return_value = 3
>>> mock()
3
7 sẽ tự động sử dụng lớp con của bạn. Điều đó có nghĩa là tất cả trẻ em của
>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
19 cũng sẽ có loại
>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
19.

Các mảng làm tổ

Sử dụng bản vá làm trình quản lý ngữ cảnh là tốt, nhưng nếu bạn thực hiện nhiều bản vá, bạn có thể kết thúc với nhau với các câu lệnh thụt hơn và xa hơn về bên phải:

>>> mock = MagicMock(name='foo')
>>> mock
<MagicMock name='foo' id='...'>
>>> mock.method
<MagicMock name='foo.method' id='...'>
1

Với các chức năng

>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
21 ____221 và các phương thức vá lỗi: Bắt đầu và dừng chúng ta có thể đạt được hiệu ứng tương tự mà không cần thụt lề lồng nhau. Một phương pháp trợ giúp đơn giản,
>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
22, đặt bản vá vào vị trí và trả về giả tạo cho chúng tôi:patch methods: start and stop we can achieve the same effect without the nested indentation. A simple helper method,
>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
22, puts the patch in place and returns the created mock for us:

>>> mock = MagicMock(name='foo')
>>> mock
<MagicMock name='foo' id='...'>
>>> mock.method
<MagicMock name='foo.method' id='...'>
2

Chế giễu một từ điển với ma thuật

Bạn có thể muốn chế giễu một từ điển hoặc đối tượng container khác, ghi lại tất cả quyền truy cập vào nó trong khi nó vẫn hoạt động như một từ điển.

Chúng ta có thể làm điều này với

>>> expected = [call.method(), call.attribute.method(10, x=53)]
>>> mock.mock_calls == expected
True
9, sẽ hoạt động như một từ điển và sử dụng
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
05 để ủy thác truy cập từ điển đến một từ điển thực sự nằm dưới sự kiểm soát của chúng tôi.

Khi các phương thức

>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
25 và
>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
26 của
>>> expected = [call.method(), call.attribute.method(10, x=53)]
>>> mock.mock_calls == expected
True
9 của chúng tôi được gọi (truy cập từ điển bình thường) thì
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
05 được gọi bằng khóa (và trong trường hợp
>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
29 cũng có giá trị). Chúng tôi cũng có thể kiểm soát những gì được trả lại.

Sau khi

>>> expected = [call.method(), call.attribute.method(10, x=53)]
>>> mock.mock_calls == expected
True
9 đã được sử dụng, chúng tôi có thể sử dụng các thuộc tính như
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
98 để khẳng định về cách sử dụng từ điển:

>>> mock = MagicMock(name='foo')
>>> mock
<MagicMock name='foo' id='...'>
>>> mock.method
<MagicMock name='foo.method' id='...'>
3

Ghi chú

Một giải pháp thay thế cho việc sử dụng

>>> expected = [call.method(), call.attribute.method(10, x=53)]
>>> mock.mock_calls == expected
True
9 là sử dụng
>>> expected = [call.method(), call.attribute.method(10, x=53)]
>>> mock.mock_calls == expected
True
6 và chỉ cung cấp các phương thức ma thuật mà bạn đặc biệt muốn:

>>> mock = MagicMock(name='foo')
>>> mock
<MagicMock name='foo' id='...'>
>>> mock.method
<MagicMock name='foo.method' id='...'>
4

Tùy chọn thứ ba là sử dụng

>>> expected = [call.method(), call.attribute.method(10, x=53)]
>>> mock.mock_calls == expected
True
9 nhưng chuyển trong
>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
35 làm đối số thông số kỹ thuật (hoặc spec_set) để
>>> expected = [call.method(), call.attribute.method(10, x=53)]
>>> mock.mock_calls == expected
True
9 được tạo chỉ có các phương thức ma thuật từ điển có sẵn:

>>> mock = MagicMock(name='foo')
>>> mock
<MagicMock name='foo' id='...'>
>>> mock.method
<MagicMock name='foo.method' id='...'>
5

Với các chức năng tác dụng phụ này,

>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
37 sẽ hoạt động như một từ điển bình thường nhưng ghi lại quyền truy cập. Nó thậm chí còn tăng một
>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
38 nếu bạn cố gắng truy cập vào một khóa không tồn tại.

>>> mock = MagicMock(name='foo')
>>> mock
<MagicMock name='foo' id='...'>
>>> mock.method
<MagicMock name='foo.method' id='...'>
6

Sau khi nó được sử dụng, bạn có thể đưa ra các xác nhận về quyền truy cập bằng các phương thức và thuộc tính giả thông thường:

>>> mock = MagicMock(name='foo')
>>> mock
<MagicMock name='foo' id='...'>
>>> mock.method
<MagicMock name='foo.method' id='...'>
7

Các lớp con giả và các thuộc tính của chúng

Có nhiều lý do tại sao bạn có thể muốn phân lớp

>>> expected = [call.method(), call.attribute.method(10, x=53)]
>>> mock.mock_calls == expected
True
6. Một lý do có thể là để thêm các phương pháp trợ giúp. Ở đây, một ví dụ ngớ ngẩn:

>>> mock = MagicMock(name='foo')
>>> mock
<MagicMock name='foo' id='...'>
>>> mock.method
<MagicMock name='foo.method' id='...'>
8

Hành vi tiêu chuẩn cho các trường hợp

>>> expected = [call.method(), call.attribute.method(10, x=53)]
>>> mock.mock_calls == expected
True
6 là các thuộc tính và các chế độ giá trị trả về cùng loại với giả mà chúng được truy cập. Điều này đảm bảo rằng các thuộc tính
>>> expected = [call.method(), call.attribute.method(10, x=53)]
>>> mock.mock_calls == expected
True
6 là các thuộc tính
>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
42 và
>>> expected = [call.method(), call.attribute.method(10, x=53)]
>>> mock.mock_calls == expected
True
9 là
>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
44 2. Vì vậy, nếu bạn phân lớp để thêm các phương thức trợ giúp thì chúng cũng sẽ có sẵn trên các thuộc tính và trả lại giá trị giả của các trường hợp của lớp con của bạn.

>>> mock = MagicMock(name='foo')
>>> mock
<MagicMock name='foo' id='...'>
>>> mock.method
<MagicMock name='foo.method' id='...'>
9

Đôi khi điều này là bất tiện. Ví dụ, một người dùng đang bị chế giễu để tạo một bộ chuyển đổi xoắn. Có điều này áp dụng cho các thuộc tính quá thực sự gây ra lỗi.

>>> expected = [call.method(), call.attribute.method(10, x=53)]
>>> mock.mock_calls == expected
True
6 (trong tất cả các hương vị của nó) sử dụng một phương thức gọi là
>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
46 để tạo các loại khóa con của các thuộc tính và các giá trị trả về. Bạn có thể ngăn chặn lớp con của bạn được sử dụng cho các thuộc tính bằng cách ghi đè phương thức này. Chữ ký là nó lấy các đối số từ khóa tùy ý (
>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
47) sau đó được truyền vào hàm tạo giả:

>>> mock = MagicMock()
>>> mock.method()
<MagicMock name='mock.method()' id='...'>
>>> mock.attribute.method(10, x=53)
<MagicMock name='mock.attribute.method()' id='...'>
>>> mock.mock_calls
[call.method(), call.attribute.method(10, x=53)]
0

2

Một ngoại lệ cho quy tắc này là các chế giễu không thể gọi được. Các thuộc tính sử dụng biến thể có thể gọi được vì nếu không thì giả không thể gọi có thể có các phương thức có thể gọi được.

Nhập khẩu chế giễu với Patch.Dict¶

Một tình huống mà chế giễu có thể khó khăn là nơi bạn có một nhập khẩu cục bộ bên trong một chức năng. Chúng khó chế giễu hơn vì chúng không sử dụng một đối tượng từ không gian tên mô -đun mà chúng ta có thể vá.

Nói chung nhập khẩu địa phương là phải tránh. Đôi khi chúng được thực hiện để ngăn chặn các phụ thuộc tròn, thường có cách tốt hơn nhiều để giải quyết vấn đề (tái cấu trúc mã) hoặc để ngăn chặn chi phí phía trước của Hồi giáo bằng cách trì hoãn việc nhập khẩu. Điều này cũng có thể được giải quyết theo những cách tốt hơn so với nhập cục bộ vô điều kiện (lưu trữ mô -đun dưới dạng thuộc tính lớp hoặc mô -đun và chỉ thực hiện nhập khi sử dụng đầu tiên).

Điều đó sang một bên có một cách để sử dụng

>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
37 để ảnh hưởng đến kết quả nhập khẩu. Nhập dữ liệu tìm thấy một đối tượng từ từ điển
>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
49. Lưu ý rằng nó lấy một đối tượng, không cần phải là một mô -đun. Nhập một mô -đun cho lần đầu tiên dẫn đến một đối tượng mô -đun được đặt vào
>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
49, vì vậy thông thường khi bạn nhập một cái gì đó, bạn sẽ lấy lại một mô -đun. Điều này không cần phải là trường hợp tuy nhiên.

Điều này có nghĩa là bạn có thể sử dụng

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
29 để tạm thời đặt một chế độ giả vào vị trí trong
>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
49. Bất kỳ nhập khẩu nào trong khi bản vá này hoạt động sẽ lấy được giả. Khi bản vá hoàn tất (chức năng được trang trí thoát ra, phần thân câu lệnh đã hoàn thành hoặc
>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
53 được gọi) thì bất cứ điều gì trước đây sẽ được khôi phục an toàn.

Dưới đây, một ví dụ đã chế giễu mô -đun ‘Fooble.

>>> mock = MagicMock()
>>> mock.method()
<MagicMock name='mock.method()' id='...'>
>>> mock.attribute.method(10, x=53)
<MagicMock name='mock.attribute.method()' id='...'>
>>> mock.mock_calls
[call.method(), call.attribute.method(10, x=53)]
1

Như bạn có thể thấy

>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
54 thành công, nhưng khi thoát ra, không còn ‘fooble, còn lại trong
>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
49.

Điều này cũng hoạt động cho mẫu

>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
56:

>>> mock = MagicMock()
>>> mock.method()
<MagicMock name='mock.method()' id='...'>
>>> mock.attribute.method(10, x=53)
<MagicMock name='mock.attribute.method()' id='...'>
>>> mock.mock_calls
[call.method(), call.attribute.method(10, x=53)]
2

Với nhiều công việc hơn một chút, bạn cũng có thể chế giễu nhập khẩu gói:

>>> mock = MagicMock()
>>> mock.method()
<MagicMock name='mock.method()' id='...'>
>>> mock.attribute.method(10, x=53)
<MagicMock name='mock.attribute.method()' id='...'>
>>> mock.mock_calls
[call.method(), call.attribute.method(10, x=53)]
3

Theo dõi thứ tự các cuộc gọi và ít xác nhận cuộc gọi dài dòng

Lớp

>>> expected = [call.method(), call.attribute.method(10, x=53)]
>>> mock.mock_calls == expected
True
6 cho phép bạn theo dõi thứ tự các cuộc gọi phương thức trên các đối tượng giả của bạn thông qua thuộc tính
>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
58. Điều này không cho phép bạn theo dõi thứ tự các cuộc gọi giữa các đối tượng giả riêng biệt, tuy nhiên chúng ta có thể sử dụng
>>> mock = Mock()
>>> mock.return_value = 3
>>> mock()
3
8 để đạt được hiệu ứng tương tự.

Bởi vì chế giễu các cuộc gọi theo dõi các chế độ giả của trẻ em trong

>>> mock = Mock()
>>> mock.return_value = 3
>>> mock()
3
8 và truy cập vào một thuộc tính tùy ý của một chế giễu tạo ra một chế độ giả, chúng ta có thể tạo ra các chế giễu riêng biệt từ cha mẹ. Các cuộc gọi đến những con chó con đó sau đó sẽ được ghi lại, theo thứ tự, trong
>>> mock = Mock()
>>> mock.return_value = 3
>>> mock()
3
8 của cha mẹ:

>>> mock = MagicMock()
>>> mock.method()
<MagicMock name='mock.method()' id='...'>
>>> mock.attribute.method(10, x=53)
<MagicMock name='mock.attribute.method()' id='...'>
>>> mock.mock_calls
[call.method(), call.attribute.method(10, x=53)]
4

>>> mock = MagicMock()
>>> mock.method()
<MagicMock name='mock.method()' id='...'>
>>> mock.attribute.method(10, x=53)
<MagicMock name='mock.attribute.method()' id='...'>
>>> mock.mock_calls
[call.method(), call.attribute.method(10, x=53)]
5

>>> mock = MagicMock()
>>> mock.method()
<MagicMock name='mock.method()' id='...'>
>>> mock.attribute.method(10, x=53)
<MagicMock name='mock.attribute.method()' id='...'>
>>> mock.mock_calls
[call.method(), call.attribute.method(10, x=53)]
6

Sau đó, chúng ta có thể khẳng định về các cuộc gọi, bao gồm cả thứ tự, bằng cách so sánh với thuộc tính

>>> mock = Mock()
>>> mock.return_value = 3
>>> mock()
3
8 trên trình quản lý giả:

>>> mock = MagicMock()
>>> mock.method()
<MagicMock name='mock.method()' id='...'>
>>> mock.attribute.method(10, x=53)
<MagicMock name='mock.attribute.method()' id='...'>
>>> mock.mock_calls
[call.method(), call.attribute.method(10, x=53)]
7

Nếu

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
30 đang tạo và đặt vào vị trí, chế giễu của bạn thì bạn có thể gắn chúng vào một trình quản lý giả sử dụng phương thức
>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
64. Sau khi đính kèm các cuộc gọi sẽ được ghi lại trong
>>> mock = Mock()
>>> mock.return_value = 3
>>> mock()
3
8 của người quản lý.

>>> mock = MagicMock()
>>> mock.method()
<MagicMock name='mock.method()' id='...'>
>>> mock.attribute.method(10, x=53)
<MagicMock name='mock.attribute.method()' id='...'>
>>> mock.mock_calls
[call.method(), call.attribute.method(10, x=53)]
8

Nếu nhiều cuộc gọi đã được thực hiện, nhưng bạn chỉ quan tâm đến một chuỗi cụ thể của chúng thì một giải pháp thay thế là sử dụng phương thức

>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
66. Điều này lấy một danh sách các cuộc gọi (được xây dựng với đối tượng
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
00). Nếu chuỗi cuộc gọi đó nằm trong
>>> mock = Mock()
>>> mock.return_value = 3
>>> mock()
3
8 thì khẳng định thành công.

>>> mock = MagicMock()
>>> mock.method()
<MagicMock name='mock.method()' id='...'>
>>> mock.attribute.method(10, x=53)
<MagicMock name='mock.attribute.method()' id='...'>
>>> mock.mock_calls
[call.method(), call.attribute.method(10, x=53)]
9

Mặc dù cuộc gọi bị xích

>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
69 aren là những cuộc gọi duy nhất được thực hiện cho Mock, nhưng Assert vẫn thành công.

Đôi khi một chế giễu có thể có một số cuộc gọi được thực hiện cho nó, và bạn chỉ quan tâm đến việc khẳng định về một số cuộc gọi đó. Bạn thậm chí có thể không quan tâm đến đơn đặt hàng. Trong trường hợp này, bạn có thể chuyển

>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
70 đến
>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
71:

>>> expected = [call.method(), call.attribute.method(10, x=53)]
>>> mock.mock_calls == expected
True
0

Đối số phức tạp hơn phù hợp

Sử dụng cùng một khái niệm cơ bản như

>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
72, chúng ta có thể triển khai các trình chỉnh sửa để thực hiện các xác nhận phức tạp hơn trên các đối tượng được sử dụng làm đối số để chế giễu.

Giả sử chúng ta hy vọng một số đối tượng sẽ được chuyển đến một chế độ giả mà theo mặc định so sánh bằng nhau dựa trên nhận dạng đối tượng (đó là mặc định Python cho các lớp do người dùng xác định). Để sử dụng

>>> m = Mock()
>>> m.factory(important=True).deliver()
<Mock name='mock.factory().deliver()' id='...'>
>>> m.mock_calls[-1] == call.factory(important=False).deliver()
True
3, chúng ta sẽ cần phải vượt qua cùng một đối tượng. Nếu chúng ta chỉ quan tâm đến một số thuộc tính của đối tượng này thì chúng ta có thể tạo một trình kết hợp sẽ kiểm tra các thuộc tính này cho chúng ta.

Bạn có thể thấy trong ví dụ này cách một cuộc gọi ’tiêu chuẩn đến

>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
96 là đủ:

>>> expected = [call.method(), call.attribute.method(10, x=53)]
>>> mock.mock_calls == expected
True
1

Một chức năng so sánh cho lớp

>>> mock = Mock()
>>> mock.return_value = 3
>>> mock()
3
3 của chúng tôi có thể trông giống như thế này:

>>> expected = [call.method(), call.attribute.method(10, x=53)]
>>> mock.mock_calls == expected
True
2

Và một đối tượng Matcher có thể sử dụng các hàm so sánh như thế này cho hoạt động bình đẳng của nó sẽ trông giống như thế này:

>>> expected = [call.method(), call.attribute.method(10, x=53)]
>>> mock.mock_calls == expected
True
3

Đặt tất cả những điều này lại với nhau:

>>> expected = [call.method(), call.attribute.method(10, x=53)]
>>> mock.mock_calls == expected
True
4

>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
76 được khởi tạo với hàm so sánh của chúng tôi và đối tượng
>>> mock = Mock()
>>> mock.return_value = 3
>>> mock()
3
3 mà chúng tôi muốn so sánh với. Trong
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
96, phương pháp bình đẳng
>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
76 sẽ được gọi, so sánh đối tượng mà giả được gọi với phương pháp mà chúng tôi đã tạo ra Matcher của chúng tôi. Nếu chúng phù hợp thì
>>> class ProductionClass:
...     def method(self):
...         self.something(1, 2, 3)
...     def something(self, a, b, c):
...         pass
...
>>> real = ProductionClass()
>>> real.something = MagicMock()
>>> real.method()
>>> real.something.assert_called_once_with(1, 2, 3)
96 vượt qua và nếu họ không được nâng lên
>>> class ProductionClass:
...     def closer(self, something):
...         something.close()
...
81:

>>> expected = [call.method(), call.attribute.method(10, x=53)]
>>> mock.mock_calls == expected
True
5

Với một chút điều chỉnh, bạn có thể có chức năng so sánh trực tiếp tăng ____281 và cung cấp thông báo thất bại hữu ích hơn.

Kể từ phiên bản 1.5, thư viện thử nghiệm Python Pyhamcrest cung cấp chức năng tương tự, có thể hữu ích ở đây, dưới dạng trình mai tởm bình đẳng của nó (Hamcrest.l Library.Integration.Match_Equality).

Tác dụng phụ trong chế giễu là gì?

Tác dụng phụ - Một công cụ đa chức năng Mock's Side_effect tham số cho phép thay đổi hành vi của giả.Nó chấp nhận ba loại giá trị và thay đổi hành vi của nó cho phù hợp.allows to change the behavior of the mock. It accepts three types of values and changes its behavior accordingly.

Tác dụng phụ trong Python Mock là gì?

Tác dụng phụ Đây là những điều bạn muốn xảy ra khi chức năng giả của bạn được gọi.Các ví dụ phổ biến đang gọi một chức năng khác hoặc tăng các ngoại lệ.the things that you want to happen when your mock function is called. Common examples are calling another function or raising exceptions.

Bản vá ở Python là gì?

Trong Python, thuật ngữ bản vá khỉ đề cập đến các sửa đổi động (hoặc thời gian chạy) của một lớp hoặc mô-đun.Trong Python, chúng ta thực sự có thể thay đổi hành vi của mã khi chạy.# Monk.py.dynamic (or run-time) modifications of a class or module. In Python, we can actually change the behavior of code at run-time. # monk.py.

Magicmock là gì?

MagicMock.Các đối tượng MagicMock cung cấp một giao diện chế giễu đơn giản cho phép bạn đặt giá trị trả về hoặc hành vi khác của chức năng hoặc cuộc gọi 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, có thể gây khó chịu.provide a simple mocking interface that allows you to set the return value or other behavior of the function or object creation call that you patched. This allows you to fully define the behavior of the call and avoid creating real objects, which can be onerous.