Python Chế nhạo một hàm từ một mô-đun đã nhập


125

Tôi muốn hiểu cách sử dụng @patchmột hàm từ một mô-đun đã nhập.

Đây là nơi tôi đang ở cho đến nay.

app / mocking.py:

from app.my_module import get_user_name

def test_method():
  return get_user_name()

if __name__ == "__main__":
  print "Starting Program..."
  test_method()

app / my_module / __ init__.py:

def get_user_name():
  return "Unmocked User"

test / mock-test.py:

import unittest
from app.mocking import test_method 

def mock_get_user():
  return "Mocked This Silly"

@patch('app.my_module.get_user_name')
class MockingTestTestCase(unittest.TestCase):

  def test_mock_stubs(self, mock_method):
    mock_method.return_value = 'Mocked This Silly')
    ret = test_method()
    self.assertEqual(ret, 'Mocked This Silly')

if __name__ == '__main__':
  unittest.main()

Điều này không hoạt động như tôi mong đợi. Mô-đun "được vá" chỉ trả về giá trị chưa được sửa của get_user_name. Làm cách nào để mô phỏng các phương thức từ các gói khác mà tôi đang nhập vào một không gian tên đang được kiểm tra?


1
Câu hỏi đặt ra là về "các phương pháp hay nhất chế giễu" hoặc liệu những gì bạn đang làm có hợp lý hay không? Về điều đầu tiên, tôi muốn nói là sử dụng một thư viện chế nhạo chẳng hạn như Mock, được bao gồm trong python3.3 + as unittest.mock.
Bakuriu

Tôi đang hỏi liệu tôi có đi đúng không. Tôi đã xem xét Mock, nhưng tôi không thấy cách nào để giải quyết vấn đề cụ thể này. Có cách nào để tạo lại những gì tôi đã làm ở trên trong Mock không?
nsfyn55

Câu trả lời:


167

Khi bạn đang sử dụng trình patchtrang trí từ unittest.mockgói, bạn không vá không gian tên mà mô-đun được nhập từ (trong trường hợp này app.my_module.get_user_name), bạn đang vá nó trong không gian tên đang được kiểm tra app.mocking.get_user_name.

Để thực hiện điều trên, Mockhãy thử một số thứ như sau:

from mock import patch
from app.mocking import test_method 

class MockingTestTestCase(unittest.TestCase):

    @patch('app.mocking.get_user_name')
    def test_mock_stubs(self, test_patch):
        test_patch.return_value = 'Mocked This Silly'
        ret = test_method()
        self.assertEqual(ret, 'Mocked This Silly')

Tài liệu thư viện tiêu chuẩn bao gồm một phần hữu ích mô tả điều này.


điều này liên quan đến vấn đề của tôi. get_user_namenằm trong một mô-đun khác với test_method. Có cách nào để chế nhạo thứ gì đó trong sub_module không? Tôi đã sửa nó một cách xấu xí dưới đây.
nsfyn55

6
Nó không quan trọng get_user_nametrong một mô-đun khác test_methodvì bạn đang nhập hàm vào app.mockingchúng ở trong cùng một không gian tên.
Matti John

2
Test_patch đến từ đâu, nó chính xác là gì?
Mike G

2
test_patch được chuyển vào bởi trình trang trí bản vá và là đối tượng get_user_name bị chế nhạo (tức là một thể hiện của lớp MagicMock). Nó có thể rõ ràng hơn nếu nó được đặt tên như thế nào get_user_name_patch.
Matti John

Bạn đang tham khảo test_method như thế nào? Nó sẽ dẫn đến lỗi, NameError: global name 'test_method' không được xác định
Aditya

12

Mặc dù câu trả lời của Matti John giải quyết được vấn đề của bạn (và cũng giúp tôi, cảm ơn!), Tuy nhiên, tôi sẽ đề xuất bản địa hóa việc thay thế hàm 'get_user_name' ban đầu bằng hàm bị chế nhạo. Điều này sẽ cho phép bạn kiểm soát khi nào chức năng được thay thế và khi nào thì không. Ngoài ra, điều này sẽ cho phép bạn thực hiện nhiều thay thế trong cùng một thử nghiệm. Để làm như vậy, hãy sử dụng trạng thái 'with' theo cách khá đơn giản:

from mock import patch

class MockingTestTestCase(unittest.TestCase):

    def test_mock_stubs(self):
        with patch('app.mocking.get_user_name', return_value = 'Mocked This Silly'):
            ret = test_method()
            self.assertEqual(ret, 'Mocked This Silly')

6
Đây là loại không quan trọng đối với câu hỏi đã đặt ra. Cho dù bạn sử dụng patchnhư một người trang trí hay trình quản lý ngữ cảnh là cụ thể cho trường hợp sử dụng. Ví dụ: bạn có thể sử dụng patchnhư một người trang trí để giả lập một giá trị cho tất cả các bài kiểm tra trong một xunithoặc pytestlớp trong khi trong các trường hợp khác, nó rất hữu ích khi có quyền kiểm soát chi tiết do trình quản lý ngữ cảnh cung cấp.
nsfyn55
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.