2013-06-03 18 views
9

Tôi có một vấn đề hóc búa mà tôi dường như không thể hiểu thấu. Tôi là hiện đang viết các bài kiểm tra đơn vị cho chương trình phụ trợ tùy chỉnh django. Trên hệ thống của chúng tôi, chúng tôi thực sự có hai chương trình phụ trợ: một phụ trợ django và phụ trợ tùy chỉnh gửi yêu cầu đến API dựa trên Java trả về thông tin người dùng dưới dạng XML. Bây giờ, tôi đang viết đơn vị kiểm tra để tôi không muốn gửi yêu cầu ra ngoài hệ thống như , tôi không cố gắng kiểm tra API Java, vì vậy câu hỏi của tôi là làm cách nào tôi có thể thực hiện việc này và thử tác dụng phụ theo cách mạnh mẽ nhất.Làm sạch các máy chủ và API từ xa cho các Unittests Django

Chức năng Tôi đang thử nghiệm là một cái gì đó như thế này, nơi các thiết lập giá trị url chỉ là địa chỉ cơ sở cho máy chủ Java mà xác nhận các dữ liệu tên truy cập và mật khẩu và trả về xml, và giá trị dịch vụ là chỉ là một số ma thuật để xây dựng các truy vấn url, không quan trọng của nó đối với chúng tôi:

@staticmethod 
def get_info_from_api_with_un_pw(username, password, service=12345): 
    url = settings.AUTHENTICATE_URL_VIA_PASSWORD 
    if AUTH_FIELD == "username": 
     params = {"nick": username, "password": password} 
    elif AUTH_FIELD == "email": 
     params = {"email": username, "password": password} 
    params["service"] = service 
    encoded_params = urlencode([(k, smart_str(v, "latin1")) for k, v in params.items()]) 
    try: 
     # get the user's data from the api 
     xml = urlopen(url + encoded_params).read() 
     userinfo = dict((e.tag, smart_unicode(e.text, strings_only=True)) 
         for e in ET.fromstring(xml).getchildren()) 
     if "nil" in userinfo: 
      return userinfo 
     else: 
      return None 

vì vậy, chúng tôi nhận được xml, phân tích nó thành một dict và nếu con số không quan trọng là hiện tại sau đó chúng ta có thể trả lại dict và mang về hạnh phúc và được chứng thực. Rõ ràng, một trong những giải pháp được chỉ để tìm một cách nào đó ghi đè lên hoặc monkeypatch logic trong biến xml, tôi thấy câu trả lời này:

How can one mock/stub python module like urllib

tôi cố gắng thực hiện một cái gì đó như thế, nhưng các chi tiết có là rất sơ sài và tôi dường như không thể làm việc đó.

Tôi cũng chiếm được đáp ứng xml và đặt nó trong một tập tin địa phương trong thư mục thử nghiệm với ý định tìm kiếm một cách để sử dụng như là một phản ứng giả được truyền vào tham số url của hàm kiểm tra, một cái gì đó như thế này sẽ ghi đè lên các url:

@override_settings(AUTHENTICATE_URL_VIA_PASSWORD=(os.path.join(os.path.dirname(__file__), "{0}".format("response.xml")))) 
def test_get_user_info_username(self): 
    self.backend = RemoteAuthBackend() 
    self.backend.get_info_from_api_with_un_pw("user", "pass") 

Nhưng điều đó cũng cần phải tính đến logic xây dựng url rằng chức năng xác định, (tức là "url + encoded_params"). Một lần nữa, tôi có thể đổi tên tệp phản hồi giống với url được kết nối nhưng điều này đang trở thành ít giống như một bài kiểm tra đơn vị tốt cho chức năng và nhiều phần "lừa gạt", toàn bộ điều ngày càng trở nên ngày càng nhiều giòn tất cả các thời gian với các giải pháp này, và nó thực sự chỉ là một vật cố anyway, đó cũng là một cái gì đó tôi muốn tránh nếu ở tất cả có thể.

Tôi cũng tự hỏi nếu có thể có một cách để phục vụ xml trên máy chủ phát triển django và sau đó chỉ các chức năng tại đó? Nó có vẻ như một giải pháp an toàn hơn, nhưng nhiều googling đã cho tôi không có manh mối nếu một điều như vậy sẽ là có thể hoặc khuyến khích và thậm chí sau đó tôi không nghĩ rằng đó sẽ là một thử nghiệm để chạy bên ngoài môi trường phát triển. Vì vậy, lý tưởng, tôi cần để có thể bằng cách nào đó giả lập một "máy chủ" để thay thế Java API trong cuộc gọi chức năng, hoặc bằng cách nào đó phục vụ lên một số tải trọng xml mà chức năng có thể mở dưới dạng url của nó hoặc monkeypatch chức năng từ bản thân kiểm tra, hoặc ...

Thư viện mô phỏng có các công cụ thích hợp để làm những việc như vậy không?

http://www.voidspace.org.uk/python/mock

Vì vậy, có hai điểm cho câu hỏi này 1) Tôi muốn giải quyết vấn đề cụ thể của tôi trong một cách sạch sẽ, và quan trọng hơn 2) những gì là thực hiện những điều tốt nhất cho sạch viết đơn vị Django khi bạn là phụ thuộc vào dữ liệu, cookie, v.v ... để xác thực người dùng từ một API từ xa từ xa nằm ngoài miền của bạn?

Trả lời

1

Thư viện mô phỏng sẽ hoạt động nếu được sử dụng đúng cách. Tôi thích thư viện minimock và tôi đã viết một testcase đơn vị cơ sở nhỏ (minimocktest) giúp điều này.

Nếu bạn muốn tích hợp testcase này với Django để kiểm tra urllib bạn có thể làm điều đó như sau:

from minimocktest import MockTestCase 
from django.test import TestCase 
from django.test.client import Client 

class DjangoTestCase(TestCase, MockTestCase): 
    ''' 
    A TestCase class that combines minimocktest and django.test.TestCase 
    ''' 

    def _pre_setup(self): 
     MockTestCase.setUp(self) 
     TestCase._pre_setup(self) 
     # optional: shortcut client handle for quick testing 
     self.client = Client() 

    def _post_teardown(self): 
     TestCase._post_teardown(self) 
     MockTestCase.tearDown(self) 

Bây giờ bạn có thể sử dụng testcase này thay vì sử dụng các trường hợp thử nghiệm Django trực tiếp:

class MySimpleTestCase(DjangoTestCase): 
    def setUp(self): 
     self.file = StringIO.StringIO('MiniMockTest') 
     self.file.close = self.Mock('file_close_function') 
    def test_urldump_dumpsContentProperly(self): 
     self.mock('urllib2.urlopen', returns=self.file) 
     self.assertEquals(urldump('http://pykler.github.com'), 'MiniMockTest') 
     self.assertSameTrace('\n'.join([ 
      "Called urllib2.urlopen('http://pykler.github.com')", 
      "Called file_close_function()", 
     ])) 
     urllib2.urlopen('anything') 
     self.mock('urllib2.urlopen', returns=self.file, tracker=None) 
     urllib2.urlopen('this is not tracked') 
     self.assertTrace("Called urllib2.urlopen('anything')") 
     self.assertTrace("Called urllib2.urlopen('this is mocked but not tracked')", includes=False) 
     self.assertSameTrace('\n'.join([ 
      "Called urllib2.urlopen('http://pykler.github.com')", 
      "Called file_close_function()", 
      "Called urllib2.urlopen('anything')", 
     ])) 
+0

Trong trường hợp của bạn, bạn sẽ muốn mô phỏng như sau: 'mô hình nhập; self.mock ('models.urlopen') 'vì có vẻ như bạn đã nhập nó như sau trong tập tin mô hình của bạn' từ urllib import urlopen'. – Pykler

+1

Ah, thật tuyệt, có vẻ như chế nhạo như vậy chỉ là vé thôi. Cảm ơn rất nhiều! – osman

0

Đây là những điều cơ bản của giải pháp mà tôi đã kết thúc với hồ sơ. Tôi đã sử dụng thư viện Mock chính nó chứ không phải là Mockito cuối cùng, nhưng ý tưởng là như nhau:

from mock import patch 

@override_settings(AUTHENTICATE_LOGIN_FIELD="username") 
@patch("mymodule.auth_backend.urlopen") 
def test_get_user_info_username(self, urlopen_override): 
    response = "file://" + os.path.join(os.path.dirname(__file__), "{0}".format("response.xml")) 
    # mock patch replaces API call 
    urlopen_override.return_value = urlopen(response) 
    # call the patched object 
    userinfo = RemoteAuthBackend.get_info_from_api_with_un_pw("user", "pass") 
    assert_equal(type(userinfo), dict) 
    assert_equal(userinfo["nick"], "user") 
    assert_equal(userinfo["pass"], "pass") 
Các vấn đề liên quan