2015-10-26 12 views
7

Python là một ngôn ngữ tương đối mới đối với tôi. Đơn vị kiểm tra và phụ thuộc Injection là một cái gì đó mà tôi đã làm cho một thời gian ngắn, vì vậy tôi quen thuộc với nó từ một C# phối cảnh.Cách thực hiện tiêm phụ thuộc cơ bản bằng Python (cho mục đích chế nhạo/thử nghiệm)

Gần đây, tôi đã viết đoạn mã này Python:

import requests # my dependency: http://docs.python-requests.org/en/latest/ 

class someClass: 
    def __init__(self): 
     pass 

    def __do(self, url, datagram): 
     return requests.post(self, url, datagram) 

Và sau đó tôi nhận ra rằng tôi đã vừa tạo ra một sự phụ thuộc mã hóa cứng. Bleh.

tôi đã coi việc thay đổi mã của tôi để làm "Constructor" Dependency Injection:

def __init__(self,requestLib=requests): 
    self.__request = requestLib 

def __do(self, url, datagram): 
    return self.__request.post(self, url, datagram) 

này bây giờ cho phép tôi để tiêm một/phụ thuộc mô hình giả vì lợi ích của đơn vị kiểm tra, nhưng không chắc chắn nếu điều này được coi là Python-ic. Vì vậy, tôi đang lôi cuốn cộng đồng Python để được hướng dẫn.

Một số ví dụ về cách thức Python-ic để thực hiện DI cơ bản (chủ yếu là vì viết bài kiểm tra đơn vị sử dụng Mocks/Fakes)?

PHỤ LỤC Đối với bất cứ ai tò mò về câu trả lời Mock, tôi quyết định đặt một câu hỏi riêng biệt ở đây: How does @mock.patch know which parameter to use for each mock object?

+2

Lưu ý rằng '__leading_double_underscore' gọi tên mangling, và nói chung nên tránh. Sẽ không dễ dàng hơn khi ['giả 'ra' yêu cầu'] (https://docs.python.org/3/library/unittest.mock.html) cho mô-đun được thử nghiệm hơn là tiêm nó? – jonrsharpe

+0

Tôi đọc rằng dấu gạch dưới kép __leading là để đánh dấu một phương thức riêng tư. Tôi đã nhầm? Nếu vậy, làm thế nào tôi nên đánh dấu một cái gì đó riêng tư? – Pretzel

+0

Nó sẽ dễ dàng hơn để mô phỏng các yêu cầu cho mô-đun hơn là tiêm nó? Tôi không biết. Tôi không quen với cách thức làm việc của Python, đó là lý do tại sao tôi hỏi. ;) – Pretzel

Trả lời

5

Đừng làm điều đó. Chỉ cần nhập yêu cầu như bình thường và sử dụng chúng như bình thường. Việc chuyển các thư viện làm đối số cho các nhà xây dựng của bạn là một điều thú vị để thực hiện, nhưng không phải là rất nhiệt tình và không cần thiết cho các mục đích của bạn. Để mô phỏng mọi thứ trong các bài kiểm tra đơn vị, hãy sử dụng thư viện giả. Trong python 3 nó được xây dựng vào các thư viện chuẩn

https://docs.python.org/3.4/library/unittest.mock.html

Và trong python 2 bạn cần phải cài đặt nó riêng

https://pypi.python.org/pypi/mock

mã kiểm tra của bạn sẽ giống như thế này (sử dụng python 3 phiên bản)

from unittest import TestCase 
from unittest.mock import patch 

class MyTest(TestCase): 
    @patch("mymodule.requests.post") 
    def test_my_code(self, mock_post): 
     # ... do my thing here... 
+2

Vì vậy, tôi đang cố gắng phân tích cú pháp mã của bạn. '@patch ("mymodule.requests") làm gì? Và tại sao bạn chuyển một "yêu cầu" sang phương thức "test_my_code". Ngoài ra, giả lập cho "requests.post" trông như thế nào? – Pretzel

+1

Trang trí vá thay thế yêu cầu mô-đun trong mã của bạn cho một mô hình. Mã của tôi có nhiều khả năng không chính xác, bạn sẽ phải vá từng hàm trong các yêu cầu riêng biệt để làm cho nó hoạt động. Hàm được vá được chuyển như một đối số cho phép thử, vì vậy bạn có thể thực hiện các xác nhận chống lại nó. Đọc các tài liệu để unittest và giả lập để biết thêm thông tin về cách sử dụng của chúng. –

+0

Cảm ơn sự giúp đỡ. Tôi đã cho bạn dấu kiểm. :) – Pretzel

0

Trong khi tiêm mô-đun yêu cầu có thể hơi quá nhiều, nó là một p rất tốt ractice để có một số phụ thuộc như tiêm.

Có thể trường hợp đó là một khung chính thức chỉ là những gì bạn cần. Đối với điều đó có các mô-đun tuyệt vời ra có chẳng hạn như Injector.

Cách tiếp cận tối giản hơn và thẳng về phía trước sẽ là sử dụng trang trí để thực hiện công việc cho bạn. Có một số mô-đun cho rằng out there.

Tôi duy trì một mô-đun như vậy: Injectable, cung cấp trình trang trí Python 3 @autowired để cho phép phun phụ thuộc dễ dàng và sạch sẽ.

Những điểm chính của trang trí này là rằng:

  • chức năng không phải là nhận thức được autowiring ở tất cả
  • phụ thuộc có thể được lười biếng khởi
  • người gọi là có thể vượt qua một cách rõ ràng các trường hợp phụ thuộc nếu muốn

về cơ bản bạn bật mã như này:

def __init__(self, *, model: Model = None, service: Service = None): 
    if model is None: 
     model = Model() 

    if service is None: 
     service = Service() 

    self.model = model 
    self.service = service 
    # actual code 

vào này:

@autowired 
def __init__(self, *, model: Model, service: Service): 
    self.model = model 
    self.service = service 
    # actual code 

Không phức tạp, không có thiết lập, không có công việc được thực thi.

Các vấn đề liên quan