Mock vs MagicMock


138

Hiểu biết của tôi là MagicMock là một superset của Mock tự động thực hiện "phương pháp ma thuật", do đó liên tục cung cấp hỗ trợ cho các danh sách, lặp đi lặp lại ... Vậy lý do cho Mock đơn giản tồn tại là gì? Không phải đó chỉ là một phiên bản rút gọn của MagicMock mà thực tế có thể bị bỏ qua sao? Liệu Mock lớp biết bất kỳ thủ thuật mà không có sẵn trong MagicMock ?

Câu trả lời:


99

Lý do cho Mock đồng bằng hiện có là gì?

Tác giả của Mock, Michael Foord, đã trả lời một câu hỏi rất giống nhau tại Pycon 2011 (31:00) :

Q: Tại sao MagicMock tạo ra một thứ riêng biệt thay vì chỉ gấp khả năng vào đối tượng giả mặc định?

Trả lời: Một câu trả lời hợp lý là cách thức hoạt động của MagicMock là nó cấu hình trước tất cả các phương thức giao thức này bằng cách tạo các Giả lập mới và thiết lập chúng, vì vậy, nếu mọi giả định mới tạo ra một loạt các giả mới và đặt chúng thành các phương thức giao thức và sau đó tất cả các giao thức đó các phương thức đã tạo ra một loạt các giả và đặt chúng vào các phương thức giao thức của chúng, bạn đã có đệ quy vô hạn ...

Điều gì xảy ra nếu bạn muốn truy cập giả của mình dưới dạng đối tượng chứa lỗi - bạn không muốn điều đó hoạt động? Nếu mọi giả đều tự động có mọi phương thức giao thức, thì việc đó sẽ trở nên khó khăn hơn nhiều. Ngoài ra, MagicMock thực hiện một số cấu hình sẵn này cho bạn, thiết lập các giá trị trả về có thể không phù hợp, vì vậy tôi nghĩ sẽ tốt hơn nếu có sự tiện lợi này có mọi thứ được cấu hình sẵn và có sẵn cho bạn, nhưng bạn cũng có thể sử dụng một bản giả đối tượng và chỉ cấu hình các phương thức ma thuật mà bạn muốn tồn tại ...

Câu trả lời đơn giản là: chỉ cần sử dụng MagicMock ở mọi nơi nếu đó là hành vi bạn muốn.


12
Tôi nghĩ rằng một câu trả lời tốt hơn là: Sử dụng MagicMock nếu bạn biết bạn đang làm gì, nếu không hãy sử dụng Mock.
laike9m

56

Với Mock, bạn có thể giả lập các phương thức ma thuật nhưng bạn phải xác định chúng. MagicMock có "triển khai mặc định của hầu hết các phương thức ma thuật." .

Nếu bạn không cần thử nghiệm bất kỳ phương pháp ma thuật nào, Mock là đầy đủ và không mang lại nhiều điều không liên quan vào các thử nghiệm của bạn. Nếu bạn cần thử nghiệm nhiều phương pháp ma thuật, MagicMock sẽ giúp bạn tiết kiệm thời gian.


Chắc chắn tôi đã đọc tài liệu. Điều đó không trả lời câu hỏi của tôi - tại sao phải bận tâm với Mock đơn giản nếu MagicMock thực hiện chính xác như vậy cộng với nhiều hơn nữa? Tôi không thấy bất kỳ thứ gì lạ trong các bài kiểm tra của mình - chỉ cần sử dụng tên khác và đó là tên đó. Vậy bắt ở đâu?
Vladimir Ignatov

39
Các thử nghiệm phải là tối thiểu và các đối tượng giả phải có chức năng tối thiểu để bạn chắc chắn chính xác những gì bạn đang thử nghiệm. Nếu bạn sử dụng MagicMock chỉ vì làm được nhiều hơn nhưng bạn không kiểm tra rõ ràng tất cả những gì "nhiều hơn", bạn có nguy cơ thử nghiệm thất bại do hành vi MagicMock mặc định. Thất bại này có thể phản ánh điều gì đó về mặc định của MagicMock hơn là điều mà nó đáng lẽ phải chế giễu. Thậm chí tệ hơn, bạn có nguy cơ thử nghiệm thành công khi đáng lẽ nó phải thất bại. Rủi ro là nhỏ nhưng nếu điều này xảy ra sẽ lãng phí rất nhiều thời gian của bạn.
Sean Redmond

1
Tôi nghĩ về nó giống như sử dụng JS vs Jquery đơn giản. Chắc chắn, bạn có thể sử dụng Jquery để thực hiện tất cả JS của mình, nhưng trong một số trường hợp, bạn chỉ muốn sử dụng công cụ tối thiểu cần thiết để hoàn thành công việc. Tôi thấy những trường hợp đó thường là cực kỳ đơn giản hoặc cực kỳ phức tạp.
rúc vào

49

Để bắt đầu, MagicMocklà một lớp con của Mock.

class MagicMock(MagicMixin, Mock)

Do đó, MagicMock cung cấp mọi thứ mà Mock cung cấp và hơn thế nữa. Thay vì nghĩ về Mock như là một phiên bản rút gọn của MagicMock, hãy nghĩ về MagicMock như một phiên bản mở rộng của Mock. Điều này sẽ giải quyết các câu hỏi của bạn về lý do tại sao Mock tồn tại và Mock cung cấp những gì trên MagicMock.

Thứ hai, MagicMock cung cấp các triển khai mặc định của nhiều / hầu hết các phương thức ma thuật, trong khi Mock thì không. Xem ở đây để biết thêm thông tin về các phương pháp ma thuật được cung cấp.

Một số ví dụ về các phương pháp ma thuật được cung cấp:

>>> int(Mock())
TypeError: int() argument must be a string or a number, not 'Mock'
>>> int(MagicMock())
1
>>> len(Mock())
TypeError: object of type 'Mock' has no len()
>>> len(MagicMock())
0

Và những thứ có thể không trực quan (ít nhất là không trực quan với tôi):

>>> with MagicMock():
...     print 'hello world'
...
hello world
>>> MagicMock()[1]
<MagicMock name='mock.__getitem__()' id='4385349968'>

Bạn có thể "thấy" các phương thức được thêm vào MagicMock khi các phương thức đó được gọi lần đầu tiên:

>>> magic1 = MagicMock()
>>> dir(magic1)
['assert_any_call', 'assert_called_once_with', ...]
>>> int(magic1)
1
>>> dir(magic1)
['__int__', 'assert_any_call', 'assert_called_once_with', ...]
>>> len(magic1)
0
>>> dir(magic1)
['__int__', '__len__', 'assert_any_call', 'assert_called_once_with', ...]

Vậy, tại sao không sử dụng MagicMock mọi lúc?

Câu hỏi trở lại với bạn là: Bạn có ổn với việc triển khai phương thức ma thuật mặc định không? Ví dụ, nó có ổn mocked_object[1]để không lỗi không? Bạn có ổn với bất kỳ hậu quả ngoài ý muốn do việc triển khai phương pháp ma thuật đã có không?

Nếu câu trả lời cho những câu hỏi này là có, thì hãy tiếp tục và sử dụng MagicMock. Nếu không, dính vào Mock.



3

Tôi đã tìm thấy một trường hợp cụ thể khác, nơi đơn giản Mock có thể trở nên hữu ích hơn MagicMock:

In [1]: from unittest.mock import Mock, MagicMock, ANY
In [2]: mock = Mock()
In [3]: magic = MagicMock()
In [4]: mock.foo == ANY
Out[4]: True
In [5]: magic.foo == ANY
Out[5]: False

So sánh với ANYcó thể hữu ích, ví dụ, so sánh hầu hết mọi khóa giữa hai từ điển trong đó một số giá trị được tính bằng cách sử dụng giả.

Điều này sẽ hợp lệ nếu bạn đang sử dụng Mock:


self.assertDictEqual(my_dict, {
  'hello': 'world',
  'another': ANY
})

trong khi nó sẽ tăng AssertionErrornếu bạn đã sử dụngMagicMock

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.