2009-05-25 28 views
129

Tôi muốn viết một bài kiểm tra đơn vị cho một lệnh Django manage.py thực hiện một thao tác phụ trợ trên một bảng cơ sở dữ liệu. Làm thế nào tôi sẽ gọi lệnh quản lý trực tiếp từ mã?Làm thế nào tôi có thể gọi lệnh tùy chỉnh Django manage.py trực tiếp từ trình điều khiển thử nghiệm?

Tôi không muốn thực hiện lệnh trên vỏ hệ điều hành từ tests.py vì tôi không thể sử dụng môi trường thử nghiệm được thiết lập bằng cách sử dụng kiểm tra manage.py (kiểm tra cơ sở dữ liệu, kiểm tra email giả mạo, vv .. .)

Trả lời

237

Cách tốt nhất để kiểm tra những thứ như vậy - trích xuất chức năng cần thiết từ chính lệnh đó sang hàm hoặc lớp độc lập. Nó giúp trừu tượng từ "công cụ thực hiện lệnh" và viết kiểm tra mà không cần các yêu cầu bổ sung.

Nhưng nếu bạn bởi một số lý do không thể tách lệnh hình thức logic bạn có thể gọi nó từ bất kỳ mã sử dụng call_command phương pháp như thế này:

from django.core.management import call_command 

call_command('my_command', 'foo', bar='baz') 
+17

+1 để đặt logic có thể kiểm tra ở nơi khác (phương pháp mô hình? Phương pháp quản lý? Chức năng độc lập?) Để bạn không cần phải gây rối với máy móc cuộc gọi. Cũng làm cho chức năng dễ sử dụng hơn. –

+30

Thậm chí nếu bạn trích xuất logic, chức năng này vẫn hữu ích để kiểm tra hành vi lệnh cụ thể của bạn, như đối số bắt buộc và để đảm bảo nó gọi hàm phù thủy thư viện của bạn thực hiện công việc thực. –

+0

Đoạn mở đầu áp dụng cho trường hợp _any_ ranh giới. Di chuyển mã logic biz của bạn ra khỏi mã bị ràng buộc để giao tiếp với một cái gì đó, chẳng hạn như người dùng. Tuy nhiên, nếu bạn viết dòng mã, nó có thể có một lỗi, vì vậy kiểm tra thực sự nên đạt được đằng sau bất kỳ ranh giới. – Phlip

19

Thay vì làm các trick call_command, bạn có thể chạy nhiệm vụ của bạn bằng cách thực hiện:

from myapp.management.commands import my_management_task 
cmd = my_management_task.Command() 
opts = {} # kwargs for your command -- lets you override stuff for testing... 
cmd.handle_noargs(**opts) 
+8

Tại sao bạn sẽ làm điều này khi call_command cũng cung cấp để chụp stdin, stdout, stderr? Và khi tài liệu chỉ định đúng cách để làm điều này? – boatcoder

+12

Đó là một câu hỏi rất hay.Ba năm trước có lẽ tôi đã có một câu trả lời cho bạn;) – Nate

+0

Ditto Nate - khi câu trả lời của ông là những gì tôi tìm thấy một năm rưỡi trước đây - tôi chỉ xây dựng trên nó ... –

1

Xây dựng về câu trả lời của Nate tôi có điều này:

def make_test_wrapper_for(command_module): 
    def _run_cmd_with(*args): 
     """Run the possibly_add_alert command with the supplied arguments""" 
     cmd = command_module.Command() 
     (opts, args) = OptionParser(option_list=cmd.option_list).parse_args(list(args)) 
     cmd.handle(*args, **vars(opts)) 
    return _run_cmd_with 

Cách sử dụng:

from myapp.management import mycommand 
cmd_runner = make_test_wrapper_for(mycommand) 
cmd_runner("foo", "bar") 

Lợi thế ở đây là nếu bạn đã sử dụng tùy chọn bổ sung và OptParse, điều này sẽ sắp xếp cho bạn. Nó không hoàn toàn hoàn hảo - và nó chưa có đầu ra ống - nhưng nó sẽ sử dụng cơ sở dữ liệu thử nghiệm. Sau đó bạn có thể kiểm tra các hiệu ứng cơ sở dữ liệu.

Tôi chắc chắn sử dụng Micheal Foords mô-đun giả và cũng rewiring stdout trong suốt thời gian của một thử nghiệm có nghĩa là bạn có thể nhận được một số ra của kỹ thuật này nhiều quá - kiểm tra đầu ra, điều kiện xuất cảnh, vv

+2

Tại sao bạn lại gặp rắc rối này thay vì chỉ sử dụng call_command? – boatcoder

12

sau mã:

from django.core.management import call_command 
call_command('collectstatic', verbosity=3, interactive=False) 
call_command('migrate', 'myapp', verbosity=3, interactive=False) 

... bằng các lệnh sau gõ vào terminal:

$ ./manage.py collectstatic --noinput -v 3 
$ ./manage.py migrate myapp --noinput -v 3 

Xem running management commands from django docs.

5

Django documentation on the call_command không đề cập đến số out phải được chuyển hướng đến sys.stdout. Mã ví dụ nên đọc:

from django.core.management import call_command 
from django.test import TestCase 
from django.utils.six import StringIO 
import sys 

class ClosepollTest(TestCase): 
    def test_command_output(self): 
     out = StringIO() 
     sys.stdout = out 
     call_command('closepoll', stdout=out) 
     self.assertIn('Expected output', out.getvalue()) 
Các vấn đề liên quan