Thông thường, phần mềm chúng tôi viết tương tác trực tiếp với những gì chúng tôi gọi là dịch vụ "bẩn". Trong điều khoản của Giáo dân. các dịch vụ quan trọng đối với ứng dụng Python của chúng tôi, nhưng tương tác của chúng có tác dụng phụ có chủ ý nhưng không mong muốn—tức là không mong muốn trong bối cảnh chạy thử nghiệm tự động
Chia sẻ
Chia sẻThông thường, phần mềm chúng tôi viết tương tác trực tiếp với những gì chúng tôi gọi là dịch vụ "bẩn". Trong điều khoản của Giáo dân. các dịch vụ quan trọng đối với ứng dụng Python của chúng tôi, nhưng tương tác của chúng có tác dụng phụ có chủ ý nhưng không mong muốn—tức là không mong muốn trong bối cảnh chạy thử nghiệm tự động
Bởi Naftuli Kay
Chuyên gia đã được xác minh về Kỹ thuật
Từ việc xây dựng các máy chủ TCP tùy chỉnh đến các ứng dụng tài chính quy mô lớn, bề dày kinh nghiệm của Naftuli khiến anh trở thành nhà phát triển và quản trị hệ thống hàng đầu
def test_default_model_fn[path_exists, mx_load_checkpoint, mx_module, mx_cpu]. sym = Mock[] args = Mock[] aux = Mock[] mx_load_checkpoint. return_value = [sym, args, aux] mx_context = Mock[] mx_cpu. return_value = mx_context data_name = 'foo' data_shape = [1] signature = json. bãi [[{'tên'. data_name, 'hình dạng'. data_shape}]] với bản vá ['sáu. di chuyển. nội trang. open', mock_open[read_data=chữ ký]]. Mặc địnhMXNetInferenceHandler[]. default_model_fn[MODEL_DIR] mx_load_checkpoint. khẳng định_gọi_với[os. con đường. join[MODEL_DIR, 'model'], 0] init_call = call[symbol=sym, context=mx_context, data_names=[data_name], label_names=None] khẳng định init_call trong mx_module. mô hình mock_calls = mx_module. mô hình return_value. trói buộc. khẳng định_gọi_với[for_training=False, data_shapes=[[data_name, data_shape]]] mô hình. set_params. khẳng định_gọi_với[args, aux, allow_missing=True]Hãy để chúng tôi tạo một hàm lấy json từ tệp và trả về một số dữ liệu. Trong ví dụ này, chúng tôi muốn lấy dữ liệu từ API này và trả về tên của từng hành tinh và nhiệt độ bề mặt của nó trong danh sách
Thay vì tạo một tệp giả, chúng ta có thể giới hạn bản thân trong chuỗi ngắn chỉ với thông tin cần thiết
Nhưng tôi không muốn mở một tập tin thực. Tôi muốn mô phỏng phần mở đầu và nội dung của tệp. Điều này là thanh lịch có thể với
Điều này thay thế việc sử dụng open[]
Điều này hoạt động với cả open[]
được gọi trực tiếp như thế này
file = open['file/path', r]
và với một trình quản lý bối cảnh như thế này
with open['file/path', r] as _file: # ...
Sử dụng mock_open
Xem để biết thêm chi tiết
Chúng tôi sẽ sử dụng bản vá với tham số
file = open['file/path', r]0, vì vậy mục tiêu được thay thế bằng một đối tượng mock_open
mock_open[]
có một tham số gọi là
file = open['file/path', r]2 là một chuỗi cho các phương thức
file = open['file/path', r]3,
file = open['file/path', r]4 và
file = open['file/path', r]5 của tệp được mở
Đây là cách giả lập việc mở và đọc tệp bằng trình quản lý ngữ cảnh
with patch['__main__.open', new=mock_open[read_data='Fooooo']] as _file: # do your call to path 'foo/bar' _file.assert_called_once_with['foo/bar', 'r']
Câu hỏi thường gặp về mã này
Whatafuck là một trình quản lý bối cảnh? . Thêm chi tiết tại đây
Cái quái gì vậy
file = open['file/path', r]7? . Tuy nhiên, trong ví dụ trên,file = open['file/path', r]7 đó chỉ mang tính chất minh họa, bởi vì tôi không chế giễu bất kỳ open[] cụ thể nào. Thêm chi tiết trong
Cái khẳng định đó là cái gì vậy? . Kiểm tra nó ra ở đây
Tôi cá là tôi khá chắc chắn rằng bạn đã sẵn sàng để thử nghiệm phương pháp của chúng tôi
file = open['file/path', r]9 ngay bây giờ
Vì vậy, hãy kiểm tra mã kiểm tra
import unittest from unittest.mock import patch, mock_open from examples.count_lines.file_reader import FileReader class TestReadFiles[unittest.TestCase]: def test_count_lines[self]: file_content_mock = """Hello World!! Hello World is in a file. A mocked file. He is not real. But he think he is. He doesn't know he is mocked""" fake_file_path = 'file/path/mock' with patch['examples.count_lines.file_reader.open'.format[__name__], new=mock_open[read_data=file_content_mock]] as _file: actual = FileReader[].count_lines[fake_file_path] _file.assert_called_once_with[fake_file_path, 'r'] expected = len[file_content_mock.split['\n']] self.assertEqual[expected, actual]
Xem mã nguồn
Viết trên tập tin
Hãy làm đơn giản nhất. Một phương thức nhận một tin nhắn và ghi nó vào một tệp được cung cấp một file_path cụ thể
class FileWriter: @staticmethod def write[file_path, content]: with open[file_path, 'w'] as file: file.write[content]
Để giả lập mở tệp và viết nội dung trên đó, chúng ta có thể sử dụng. Mô hình giả cho đối tượng này sẽ tương tự như những gì chúng ta đã thấy trước đây trong , ngoại trừ việc chúng ta không cần chuyển tham số
file = open['file/path', r]2 trong
mock_open[]
vì chúng tôi không truy xuất dữ liệu từ tệpLàm thế nào khẳng định sẽ như thế nào?
Để trả lời câu hỏi này, chúng ta cần tự hỏi mình
Chúng ta muốn kiểm tra điều gì trong chức năng này?
Theo ý kiến ảo tưởng của tôi, một trường hợp kiểm tra tốt sẽ kiểm tra xem một tệp_path cụ thể có được gọi vào ngày _______18_______ hay không, với một chế độ mở cụ thể và liệu một nội dung cụ thể có được ghi trong tệp hay không
Đối tượng thực hiện các xác nhận có thể giúp chúng tôi kiểm tra điều đó. Cái sẽ hữu ích cho chúng ta là
with open['file/path', r] as _file: # ...4
Chúng ta hãy nhìn vào bài kiểm tra?
import unittest from unittest.mock import patch, mock_open from examples.write_on_file.file_writer import FileWriter class TestFileWriter[unittest.TestCase]: def test_file_writer[self]: fake_file_path = "fake/file/path" content = "Message to write on file to be written" with patch['examples.write_on_file.file_writer.open', mock_open[]] as mocked_file: FileWriter[].write[fake_file_path, content] # assert if opened file on write mode 'w' mocked_file.assert_called_once_with[fake_file_path, 'w'] # assert if write[content] was called from the file opened # in another words, assert if the specific content was written in file mocked_file[].write.assert_called_once_with[content]
Trong thử nghiệm này, chúng tôi mô phỏng việc mở tệp bằng trình quản lý bối cảnh. Biến
with open['file/path', r] as _file: # ...5 là tệp được mở giả định