मैं टेस्ट ड्राइवर से सीधे कस्टम Django मैनेजमेन्ट कमांड कैसे कह सकता हूं?


174

मैं एक Django manage.py कमांड के लिए एक यूनिट टेस्ट लिखना चाहता हूं जो एक डेटाबेस टेबल पर बैकएंड ऑपरेशन करता है। मैं कोड से सीधे प्रबंधन आदेश कैसे लागू करूंगा?

मैं ऑपरेटिंग सिस्टम के शेल पर test.py से कमांड निष्पादित नहीं करना चाहता, क्योंकि मैं प्रबंधन वातावरण का उपयोग नहीं कर सकता, जो कि प्रबंधित कर रहा है।

जवाबों:


312

इस तरह की चीजों का परीक्षण करने का सबसे अच्छा तरीका है - कमांड से स्टैंडअलोन फ़ंक्शन या क्लास के लिए आवश्यक कार्यक्षमता निकालना। यह "कमांड निष्पादन सामान" से अमूर्त करने और अतिरिक्त आवश्यकताओं के बिना परीक्षण लिखने में मदद करता है।

लेकिन अगर आप किसी कारण से लॉजिक फॉर्म को अडॉप्ट नहीं कर सकते हैं, तो आप इसे कॉल_कमांड विधि का उपयोग करके किसी भी कोड से कॉल कर सकते हैं :

from django.core.management import call_command

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

19
+1 को परीक्षण योग्य तर्क को कहीं और रखने के लिए (मॉडल विधि? प्रबंधक विधि? स्टैंडअलोन फ़ंक्शन?) ताकि आपको call_command मशीनरी के साथ गड़बड़ करने की आवश्यकता न हो। इसके अलावा कार्यक्षमता को पुन: उपयोग करना आसान बनाता है।
कार्ल मेयर

36
यहां तक ​​कि अगर आप तर्क को निकालते हैं, तो यह फ़ंक्शन आवश्यक आदेशों की तरह, अपने कमांड विशिष्ट व्यवहार का परीक्षण करने के लिए अभी भी उपयोगी है, और यह सुनिश्चित करने के लिए कि यह आपके लाइब्रेरी फ़ंक्शन को कॉल करता है चुड़ैल असली काम करती है।
इगोर सोबेरेरा

उद्घाटन पैराग्राफ किसी भी सीमा स्थिति पर लागू होता है। अपने स्वयं के बिज़ लॉजिक कोड को उस कोड से बाहर ले जाएं जो किसी उपयोगकर्ता के साथ कुछ करने के लिए इंटरफ़ेस करने के लिए विवश है। हालांकि, यदि आप कोड की लाइन लिखते हैं, तो इसमें बग हो सकता है, इसलिए परीक्षण वास्तव में किसी भी सीमा के पीछे पहुंचना चाहिए।
Phlip

मुझे लगता है कि यह अभी भी कुछ के लिए उपयोगी है जैसे call_command('check'), सुनिश्चित करने के लिए कि सिस्टम परीक्षण एक परीक्षण में गुजर रहे हैं।
एडम बार्न्स

22

Call_command ट्रिक करने के बजाय, आप अपना कार्य चलाकर कर सकते हैं:

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)

10
आप ऐसा क्यों करेंगे जब call_command भी stdin, stdout, stderr पर कब्जा करने का प्रावधान करता है? और जब प्रलेखन ऐसा करने का सही तरीका निर्दिष्ट करता है?
नाविक

17
यह एक बहुत अच्छा सवाल है। तीन साल पहले शायद मेरे पास आपके लिए एक उत्तर होगा;)
नैट

1
Ditto Nate - जब उसका उत्तर था जो मुझे डेढ़ साल पहले मिला था - मैंने इसे केवल बनाया था ...
Danny Staple

2
खुदाई के बाद, लेकिन आज इसने मेरी मदद की: मैं हमेशा अपने कोडबेस के सभी अनुप्रयोगों (इस्तेमाल की गई Django साइट के आधार पर) का उपयोग नहीं कर रहा हूं, और call_commandपरीक्षण किए गए एप्लिकेशन को लोड करने की आवश्यकता है INSTALLED_APPS। परीक्षण प्रयोजनों के लिए ऐप लोड करने और इसे इस्तेमाल करने के बीच, मैंने इसे चुना।
मिकाइल

call_commandशायद सबसे ज्यादा लोगों को पहले प्रयास करना चाहिए। इस उत्तर ने मुझे एक समस्या को हल करने में मदद की जहाँ मुझे यूनिकोड तालिका नामों को inspectdbकमांड में पारित करने की आवश्यकता थी । python / bash कमांड लाइन args को ascii के रूप में व्याख्या कर रहे थे, और जो कि get_table_descriptiondjango में गहरी कॉल को बमबारी कर रहा था ।
bigh_29

17

निम्नलिखित कोड:

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

... टर्मिनल में टाइप किए गए निम्न आदेशों के बराबर है:

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

Django डॉक्स से रनिंग मैनेजमेंट कमांड देखें ।


14

Call_command पर Django प्रलेखन उल्लेख नहीं है कि करने में विफल रहता outपर पुनः निर्देशित किया जाना चाहिए sys.stdout। उदाहरण कोड को पढ़ना चाहिए:

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())

1

नैट के उत्तर पर बिल्डिंग मेरे पास यह है:

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

उपयोग:

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

यहाँ लाभ यह है कि यदि आपने अतिरिक्त विकल्प और OptParse का उपयोग किया है, तो यह आपके लिए हल कर देगा। यह बिल्कुल सही नहीं है - और यह अभी तक आउटपुट को पाइप नहीं करता है - लेकिन यह परीक्षण डेटाबेस का उपयोग करेगा। फिर आप डेटाबेस प्रभाव के लिए परीक्षण कर सकते हैं।

मुझे यकीन है कि माइकल फर्ड्स मॉक मॉड्यूल का उपयोग कर रहा है और एक परीक्षण की अवधि के लिए स्टडआउट का पुन: उपयोग करने का मतलब है कि आप इस तकनीक से कुछ और भी प्राप्त कर सकते हैं - आउटपुट, निकास की स्थिति आदि का परीक्षण करें।


4
आप केवल call_command का उपयोग करने के बजाय इस सभी समस्या पर क्यों जाएंगे?
बोटकोडर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.