2016-09-12 23 views
5

Tôi hiện đang đấu tranh để tìm cách tốt để chế nhạo nhiều lớp/giá trị trả về lồng nhau. Nói cách khác, tôi muốn trả lại một mô hình ma thuật mà lần lượt trả về một ma thuật giả với giá trị trả về của chính nó. Tôi đang tìm kiếm điều này tương đối cồng kềnh và đang tìm kiếm một giải pháp thanh lịch và bảo trì hơn.Làm thế nào để mô phỏng lồng nhau/nhiều lớp đối tượng trả lại trong python

Tôi đang cố gắng kiểm tra mã sau hiệu quả. URL trả về một chuỗi json rằng cần tiếp tục xử lý:

import json 
from urllib.request import url open 

def load_json(): 
    # first return value 
    response = urlopen("http://someurl.com/api/getjson") 
    # in turn, contains two nested return values for read and decode 
     response_dict = json.loads(response.read().decode('utf-8')) 

Đây là cách tôi đã chế giễu này cho đến nay, mà là cực kỳ thanh nha và làm cho bảo trì phức tạp:

class MyTestCase(TestCase): 
    @patch('load_json_path.urlopen') 
    def test_load_json(self, mock_urlopen): 
     ### trying to simplify all of this 
     # third nested return 
     mock_decode = MagicMock(return_value='["myjsondata"]') 
     # second nested return value 
     mock_response = MagicMock() 
     mock_response.read.return_value=mock_decode 
     # first nested return value 
     mock_urlopen.return_value = mock_response 
     ### trying to simplify all of this    

     load_json() 

Cuối cùng, tất cả Tôi đang cố gắng giả là dữ liệu trả về từ hàm giải mã, bắt nguồn từ hàm mở url. Điều này có thể xảy ra trong một dòng hoặc theo cách đơn giản hơn, có thể sử dụng các phương thức nhập. Lý tưởng nhất là mô hình sẽ giống như thế này trong hàm test_load_json:

mock_urlopen.__enter__.loads.__enter__.decode.return_value = '["myjsondata"]' 

Thật không may, tôi dường như không thể tìm thấy bất cứ điều gì hữu ích trong tài liệu giả. Bất kỳ trợ giúp nào được đánh giá cao.

Trả lời

9

Biến điều này dễ dàng và có thể được ghi lại. Tuy nhiên, việc đặt tên không đơn giản và cần phải biết những gì người ta đang tìm kiếm. Các cuộc gọi nhạo báng được gọi là chuỗi cuộc gọi, đó là trong thực tế tài liệu trong thư viện giả.

Trong ví dụ này, mock_urlopen sẽ trông như thế này:

mock_urlopen.return_value.read.return_value.decode.return_value = '["myjsondata"]' 

này làm việc tuyệt vời. Để biết thêm chi tiết xem phần python doc: https://docs.python.org/3/library/unittest.mock-examples.html#mocking-chained-calls

+0

Vâng, tôi sẽ không nói "đẹp" ... –

1

Tôi đã thực hiện điều này cho bạn như là một lớp helper:

from unittest.mock import Mock 

class ProxyMock: 
    """Put me for easy referral""" 
    def __init__(self, mock, _first=True): 
     self._mock_ = mock 
     self._first_ = _first 

    def __getattr__(self, name): 
     if self._first_: 
      new_mock = getattr(self._mock_, name) 
     else: 
      new_mock = getattr(self._mock_.return_value, name) 
     return ProxyMock(new_mock, _first=False) 

    def __setattr__(self, name, value): 
     if name in ("_mock_", "_first_"): 
      return super().__setattr__(name, value) 
     setattr(self._mock_, name, value) 

a = Mock() 
ProxyMock(a).b.c.return_value = 123 

assert a.b().c() == 123 
Các vấn đề liên quan