পাইথন জ্যাঙ্গোতে ইউনিট পরীক্ষা চালানোর সময় আমি লগিং কীভাবে অক্ষম করতে পারি?


168

আমি আমার জ্যাঙ্গো অ্যাপ্লিকেশনটি পরীক্ষা করতে একটি সাধারণ ইউনিট পরীক্ষা ভিত্তিক পরীক্ষা রানার ব্যবহার করছি।

আমার অ্যাপ্লিকেশনটি নিজেই সেটিংসে একটি বেসিক লগার ব্যবহার করার জন্য কনফিগার করা হয়েছে py

logging.basicConfig(level=logging.DEBUG)

এবং আমার অ্যাপ্লিকেশন কোডটিতে ব্যবহার করে:

logger = logging.getLogger(__name__)
logger.setLevel(getattr(settings, 'LOG_LEVEL', logging.DEBUG))

যাইহোক, ইউনিটেটস চালানোর সময়, আমি লগিংটি অক্ষম করতে চাই যাতে এটি আমার পরীক্ষার ফলাফলের আউটপুটকে বিশৃঙ্খলা না করে। বৈশ্বিক উপায়ে লগিং বন্ধ করার কি কোনও সহজ উপায় আছে, যাতে আমি নির্দিষ্ট পরীক্ষা চালানোর সময় অ্যাপ্লিকেশন নির্দিষ্ট লগাররা কনসোলটিতে স্টাফ লিখতে না পারে?


চলমান পরীক্ষার সময় আপনি কীভাবে লগিং সক্ষম করেছিলেন? এবং আপনি কেন জ্যাঙ্গো লগিং ব্যবহার করছেন না?
aloreলোরে

উত্তর:


249
logging.disable(logging.CRITICAL)

এর চেয়ে কম গুরুতর বা সমান স্তরের সমস্ত লগিং কলগুলি অক্ষম করবে CRITICAL। লগিং এর মাধ্যমে আবার সক্ষম করা যায়

logging.disable(logging.NOTSET)

42
এটি সুস্পষ্ট হতে পারে তবে আমি অন্য পাঠকদের উপকারের জন্য মাঝে মাঝে সুস্পষ্ট বক্তব্য রাখতে সহায়ক বলে মনে করি: আপনি লগিং করছেন এমন অ্যাপ্লিকেশনের logging.disableশীর্ষে কলটি (গ্রহণযোগ্য উত্তর থেকে) রাখবেন tests.py
সিজে গ্যাকননেট

7
আমি কলটি সেটআপে রেখেছি () তবে আপনার বক্তব্যটি ভালভাবেই নেওয়া হয়েছে।
shreddd

আপনার পরীক্ষার সেটআপ () পদ্ধতিতে বা আসল পরীক্ষায় যা আপনি লগ করতে চান তা লগ বার্তা উত্পন্ন করে।
qris

10
এবং আপনার tearDown()পদ্ধতিতে: logging.disable(logging.NOTSET)লগিংটি খুব সুন্দরভাবে স্থানে রাখে।
mlissner

34
এটি মডিউলের init .py এ স্থাপন testsকরা খুব দরকারী।
তোবি

46

যেহেতু আপনি জ্যাঙ্গোতে রয়েছেন তাই আপনি আপনার সেটিংসে এই লাইনগুলি যুক্ত করতে পারেন py

import sys
import logging

if len(sys.argv) > 1 and sys.argv[1] == 'test':
    logging.disable(logging.CRITICAL)

এইভাবে আপনাকে প্রতিটি setUp()পরীক্ষায় এই লাইনটি যুক্ত করতে হবে না ।

এইভাবে আপনার পরীক্ষার প্রয়োজনের জন্য আপনি বেশ কয়েকটি কার্যকর পরিবর্তনও করতে পারেন।

আপনার পরীক্ষাগুলিতে সুনির্দিষ্ট যোগ করার জন্য অন্য একটি "ভাল" বা "ক্লিনার" উপায় রয়েছে এবং এটি আপনার নিজের পরীক্ষার রানার তৈরি করছে।

এই জাতীয় ক্লাস তৈরি করুন:

import logging

from django.test.simple import DjangoTestSuiteRunner
from django.conf import settings

class MyOwnTestRunner(DjangoTestSuiteRunner):
    def run_tests(self, test_labels, extra_tests=None, **kwargs):

        # Don't show logging messages while testing
        logging.disable(logging.CRITICAL)

        return super(MyOwnTestRunner, self).run_tests(test_labels, extra_tests, **kwargs)

এবং এখন আপনার সেটিংসে যুক্ত করুন। পিপি ফাইল:

TEST_RUNNER = "PATH.TO.PYFILE.MyOwnTestRunner"
#(for example, 'utils.mytest_runner.MyOwnTestRunner')

এটি আপনাকে এমন একটি খুব সহজেই কার্যকর পরিবর্তন করতে দেয় যা অন্য পদ্ধতির কাছে আসে না, যা জ্যাঙ্গোকে কেবলমাত্র আপনি যে অ্যাপ্লিকেশনগুলি চান তা পরীক্ষা করে তোলে। আপনি test_labelsপরীক্ষা রানারটিতে এই লাইনটি যুক্ত করে পরিবর্তন করতে পারেন :

if not test_labels:
    test_labels = ['my_app1', 'my_app2', ...]

নিশ্চিত - এটিকে সেটিংস.পাইতে রাখলে এটি বিশ্বব্যাপী হয়ে উঠবে।

7
জাজানো ১.6++ এর জন্য দয়া করে @alukach উত্তরটি দেখুন।
হাসেক

2
কখনও কখনও ইউনিট পরীক্ষায়, আমি জোর দিয়ে বলতে চাই যে একটি ত্রুটি লগ হয়েছিল এইভাবে এই পদ্ধতিটি আদর্শ নয়। তা সত্ত্বেও, এটা হল একটি ভাল উত্তর।
সারদাথ্রিয়ন - এসই এর বিরুদ্ধে

23

বৈশ্বিক উপায়ে লগিং বন্ধ করার কি কোনও সহজ উপায় আছে, যাতে আমি নির্দিষ্ট পরীক্ষা চালানোর সময় অ্যাপ্লিকেশন নির্দিষ্ট লগাররা কনসোলটিতে স্টাফ লিখতে না পারে?

অন্যান্য উত্তরগুলি বিশ্বব্যাপী কোনও কিছু উপেক্ষা করার জন্য লগিং অবকাঠামো সেট করে "কনসোলের স্টাফ লেখার ব্যবস্থা" রোধ করে। এটি কাজ করে তবে আমি এটির কাছে একটি দৃষ্টিভঙ্গি খুব কমই দেখছি। আমার পদ্ধতির একটি কনফিগারেশন পরিবর্তন সম্পাদন করা হয়েছে যা কনসোল থেকে বেরিয়ে আসার জন্য লগগুলি রোধ করার জন্য কেবল যা প্রয়োজন does সুতরাং আমি আমার সাথে একটি কাস্টম লগিং ফিল্টার যুক্ত করব settings.py:

from logging import Filter

class NotInTestingFilter(Filter):

    def filter(self, record):
        # Although I normally just put this class in the settings.py
        # file, I have my reasons to load settings here. In many
        # cases, you could skip the import and just read the setting
        # from the local symbol space.
        from django.conf import settings

        # TESTING_MODE is some settings variable that tells my code
        # whether the code is running in a testing environment or
        # not. Any test runner I use will load the Django code in a
        # way that makes it True.
        return not settings.TESTING_MODE

এবং আমি ফিল্টারটি ব্যবহার করতে জাঙ্গো লগিংটি কনফিগার করেছি :

LOGGING = {
    'version': 1,
    'disable_existing_loggers': False,
    'filters': {
        'testing': {
            '()': NotInTestingFilter
        }
    },
    'formatters': {
        'verbose': {
            'format': ('%(levelname)s %(asctime)s %(module)s '
                       '%(process)d %(thread)d %(message)s')
        },
    },
    'handlers': {
        'console': {
            'level': 'DEBUG',
            'class': 'logging.StreamHandler',
            'filters': ['testing'],
            'formatter': 'verbose'
        },
    },
    'loggers': {
        'foo': {
            'handlers': ['console'],
            'level': 'DEBUG',
            'propagate': True,
        },
    }
}

শেষ ফলাফল: যখন আমি পরীক্ষা করছি, কনসোলে কিছুই যায় না, তবে সমস্ত কিছু একই থাকে।

কেন এটা করবেন?

আমি কোড ডিজাইন করেছি যাতে লগিংয়ের নির্দেশাবলী রয়েছে যা কেবলমাত্র নির্দিষ্ট পরিস্থিতিতে ট্রিগার করা হয় এবং যদি সমস্যাগুলি ভুল হয়ে যায় তবে ডায়াগনোসিসের জন্য আমার সঠিক ডেটা আউটপুট করা উচিত। অতএব আমি পরীক্ষা করি যে তারা যা করার কথা বলেছিল তা করে এবং সুতরাং লগিং সম্পূর্ণরূপে অক্ষম করা আমার পক্ষে কার্যকর নয়। সফ্টওয়্যারটি উত্পাদনের পরে আমি এটি দেখতে চাই না যে আমি যা ভাবি তা লগ হয় নি।

তদুপরি, কিছু পরীক্ষার দৌড়বিদ (উদাহরণস্বরূপ) পরীক্ষার সময় লগগুলি ক্যাপচার করবে এবং পরীক্ষার ব্যর্থতার সাথে লগের প্রাসঙ্গিক অংশটি আউটপুট দেবে। পরীক্ষা কেন ব্যর্থ হয়েছিল তা নির্ধারণে এটি দরকারী। যদি লগিং পুরোপুরি বন্ধ থাকে তবে ক্যাপচার করার মতো কিছুই নেই।


"আমি যে কোনও পরীক্ষার রানার ব্যবহার করি সে জ্যাঙ্গো কোডটি এমনভাবে লোড করবে যা এটি সত্য করে তোলে" " আকর্ষণীয় ... কিভাবে?
ওয়েবটিউইক্স

আমার একটি test_settings.pyফাইল রয়েছে যা আমার প্রকল্পের পাশে বসে আছে settings.py। এটি সেট করে সেট করার settings.pyমতো কিছু পরিবর্তন TESTING_MODEকরতে হবে True। আমার পরীক্ষার রানাররা এমনভাবে সংগঠিত হয়েছে যাতে test_settingsজাজানো প্রকল্প সেটিংসের জন্য লোড করা মডিউল। এটি করা যায় এমন অনেকগুলি উপায় রয়েছে। আমি সাধারণত এনভায়রনমেন্ট ভেরিয়েবল সেট সঙ্গে যেতে DJANGO_SETTINGS_MODULEকরার proj.test_settings
লুই

এটি দুর্দান্ত এবং আমি যা চাই ঠিক তাই করে। কিছু ব্যর্থ না হওয়া অবধি ইউনিটেটের সময় লগইনটি লুকিয়ে রাখে - তারপরে জ্যাঙ্গো নাক আউটপুটটি নিয়ে যায় এবং ব্যর্থতার সাথে মুদ্রণ করে। পারফেক্ট। সঙ্গে এটি একত্রিত করুন এই কিনা তা নির্ধারণ করতে ইউনিট টেস্টিং সক্রিয়।
ruuenza

21

আমি হাসেকের কাস্টম পরীক্ষা রানার ধারণাটি পছন্দ করি। এটি লক্ষ করা উচিত যে DjangoTestSuiteRunnerজাজানো ১.6++ তে আর ডিফল্ট পরীক্ষামূলক রানার নয়, এটি প্রতিস্থাপিত হয়েছে DiscoverRunner। ডিফল্ট আচরণের জন্য, পরীক্ষার রানার আরও বেশি হওয়া উচিত:

import logging

from django.test.runner import DiscoverRunner

class NoLoggingTestRunner(DiscoverRunner):
    def run_tests(self, test_labels, extra_tests=None, **kwargs):

        # disable logging below CRITICAL while testing
        logging.disable(logging.CRITICAL)

        return super(NoLoggingTestRunner, self).run_tests(test_labels, extra_tests, **kwargs)

অনেক কিছু চেষ্টা করার পরে আমি আপনার সমাধানটি খুঁজে পেয়েছি। যাইহোক আমি টেস্ট_রোনার ফাইল যেখানে মডিউলটি আমদানি করতে সক্ষম না হওয়ায় সেটিংসে পরিবর্তনশীল TEST_RUNNER সেট করতে সক্ষম নই।
বনি খরগোশ

একটি আমদানি ইস্যু মত শোনাচ্ছে। আপনি কি রানার (প্রকৃত পাইথন মডিউলটি নয়) স্ট্রিং পথে TEST_RUNNER সেট করছেন? এছাড়াও, আপনার রানার কোথায় অবস্থিত? আমার নামের একটি পৃথক অ্যাপে আমার রয়েছে helpers, যার কেবলমাত্র এমন ব্যবহার রয়েছে যা প্রকল্পের মধ্যে অন্য কোথাও থেকে আমদানি করে না।
alukach

5

আমি দেখতে পেয়েছি যে unittestকাঠামোর মধ্যে বা অনুরূপ পরীক্ষার জন্য , ইউনিট পরীক্ষায় অযাচিত লগিং নিরাপদে অক্ষম করার সবচেয়ে কার্যকর উপায় একটি নির্দিষ্ট পরীক্ষার ক্ষেত্রে setUp/ tearDownপদ্ধতিগুলিতে সক্ষম / অক্ষম করা । এটি এমন একটি লক্ষ্যকে নির্দিষ্ট করে যেখানে লগগুলি অক্ষম করা উচিত। আপনি যে ক্লাসটি পরীক্ষা করছেন তা লগারেও আপনি স্পষ্টভাবে এটি করতে পারেন।

import unittest
import logging

class TestMyUnitTest(unittest.TestCase):
    def setUp(self):
        logging.disable(logging.CRITICAL)

    def tearDown(self):
        logging.disable(logging.NOTSET)

4

আমি কেবল একটি নির্দিষ্ট পরীক্ষা পদ্ধতিতে লগিং নিষ্ক্রিয় করতে একটি সাধারণ পদ্ধতি ডেকরেটার ব্যবহার করছি।

def disable_logging(f):

    def wrapper(*args):
        logging.disable(logging.CRITICAL)
        result = f(*args)
        logging.disable(logging.NOTSET)

        return result

    return wrapper

এবং তারপরে আমি এটি নিম্নলিখিত উদাহরণ হিসাবে ব্যবহার করি:

class ScenarioTestCase(TestCase):

    @disable_logging
    test_scenario(self):
        pass

3

পদ্ধতিতে পরীক্ষাগুলিতে লগিং স্থগিত করার জন্য বেশ কয়েকটি সুন্দর এবং পরিষ্কার unittest.mock.patchপদ্ধতি রয়েছে।

foo.py :

import logging


logger = logging.getLogger(__name__)

def bar():
    logger.error('There is some error output here!')
    return True

পরীক্ষা.পি :

from unittest import mock, TestCase
from foo import bar


class FooBarTestCase(TestCase):
    @mock.patch('foo.logger', mock.Mock())
    def test_bar(self):
        self.assertTrue(bar())

এবং python3 -m unittest testsকোন লগিং আউটপুট উত্পাদন করবে।


1

কখনও কখনও আপনি লগ চান এবং কখনও কখনও না। আমার এই কোড আছেsettings.py

import sys

if '--no-logs' in sys.argv:
    print('> Disabling logging levels of CRITICAL and below.')
    sys.argv.remove('--no-logs')
    logging.disable(logging.CRITICAL)

সুতরাং আপনি যদি --no-logsবিকল্পগুলি দিয়ে পরীক্ষা চালিয়ে যান তবে আপনি কেবল criticalলগগুলি পেয়ে যাবেন :

$ python ./manage.py tests --no-logs
> Disabling logging levels of CRITICAL and below.

আপনি যদি আপনার অবিচ্ছিন্ন ইন্টিগ্রেশন প্রবাহের পরীক্ষা দ্রুত করতে চান তবে এটি খুব সহায়ক।


1

আপনি যদি চান না যে এটি বারবার সেটআপ () এবং টিয়ারডাউন () ইউনিটেস্টের জন্য (এটির কারণটি দেখতে না পান) চালু করে / বন্ধ করে দেয়, আপনি কেবল ক্লাসে একবার এটি করতে পারেন:

    import unittest
    import logging

    class TestMyUnitTest(unittest.TestCase):
        @classmethod
        def setUpClass(cls):
            logging.disable(logging.CRITICAL)
        @classmethod
        def tearDownClass(cls):
            logging.disable(logging.NOTSET)

1

যে ক্ষেত্রে আমি সাময়িকভাবে একটি নির্দিষ্ট লগার দমন করতে চাই, আমি একটি সামান্য প্রসঙ্গ পরিচালককে লিখেছি যে আমি দরকারী পেয়েছি:

from contextlib import contextmanager
import logging

@contextmanager
def disable_logger(name):
    """Temporarily disable a specific logger."""
    logger = logging.getLogger(name)
    old_value = logger.disabled
    logger.disabled = True
    try:
        yield
    finally:
        logger.disabled = old_value

তারপরে আপনি এটি ব্যবহার করুন:

class MyTestCase(TestCase):
    def test_something(self):
        with disable_logger('<logger name>'):
            # code that causes the logger to fire

এটির সুবিধা রয়েছে যে লগারটি একবারে withসম্পূর্ণ হয়ে গেলে (বা তার পূর্ববর্তী অবস্থানে ফিরে সেট) হয়ে যায় ।


1

আপনি এটি ইউনিট টেস্ট __init__.pyফাইলের জন্য শীর্ষ স্তরের ডিরেক্টরিতে রাখতে পারেন । এটি ইউনিট পরীক্ষা স্যুটে বিশ্বব্যাপী লগিং নিষ্ক্রিয় করবে।

# tests/unit/__init__.py
import logging

logging.disable(logging.CRITICAL)

0

আমার ক্ষেত্রে আমার কাছে একটি সেটিংস ফাইল রয়েছে settings/test.pyযা পরীক্ষার উদ্দেশ্যে বিশেষভাবে তৈরি করা হয়েছিল, যা দেখতে এটির মতো তা এখানে:

from .base import *

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': 'test_db'
    }
}

PASSWORD_HASHERS = (
    'django.contrib.auth.hashers.MD5PasswordHasher',
)

LOGGING = {}

আমি একজন এনভায়রনমেন্ট ভেরিয়েবল করা DJANGO_SETTINGS_MODULE=settings.testথেকে /etc/environment


0

যদি পরীক্ষা, দেব এবং উত্পাদনের জন্য আপনার কাছে আলাদা ইনিটালাইজার মডিউল থাকে তবে আপনি যে কোনও কিছু অক্ষম করতে পারেন বা এটিকে আরম্ভকারীতে পুনর্নির্দেশ করতে পারেন। আমার কাছে স্থানীয়.পি, টেস্ট.পি এবং প্রোডাকশন.পি রয়েছে যা সব সাধারণ.ই থেকে প্রাপ্ত

কমন.পি এই স্নিপেট সহ সমস্ত মূল কনফিগারেশন করে:

LOGGING = {
'version': 1,
'disable_existing_loggers': False,
'formatters': {
    'django.server': {
        '()': 'django.utils.log.ServerFormatter',
        'format': '[%(server_time)s] %(message)s',
    },
    'verbose': {
        'format': '%(levelname)s %(asctime)s %(module)s %(process)d %(thread)d %(message)s'
    },
    'simple': {
        'format': '%(levelname)s %(message)s'
    },
},
'filters': {
    'require_debug_true': {
        '()': 'django.utils.log.RequireDebugTrue',
    },
},
'handlers': {
    'django.server': {
        'level': 'INFO',
        'class': 'logging.StreamHandler',
        'formatter': 'django.server',
    },
    'console': {
        'level': 'DEBUG',
        'class': 'logging.StreamHandler',
        'formatter': 'simple'
    },
    'mail_admins': {
        'level': 'ERROR',
        'class': 'django.utils.log.AdminEmailHandler'
    }
},
'loggers': {
    'django': {
        'handlers': ['console'],
        'level': 'INFO',
        'propagate': True,
    },
    'celery.tasks': {
        'handlers': ['console'],
        'level': 'DEBUG',
        'propagate': True,
    },
    'django.server': {
        'handlers': ['django.server'],
        'level': 'INFO',
        'propagate': False,
    },
}

তারপরে টেস্ট.পিতে আমার কাছে এটি রয়েছে:

console_logger = Common.LOGGING.get('handlers').get('console')
console_logger['class'] = 'logging.FileHandler
console_logger['filename'] = './unitest.log

এটি কনসোল হ্যান্ডলারটি ফাইলহ্যান্ডলারের সাথে প্রতিস্থাপন করে এবং তারপরে এখনও লগিং পেতে পারে তবে আমাকে প্রোডাকশন কোড বেসটি স্পর্শ করতে হবে না।


0

আপনি যদি ব্যবহার করছেন pytest:

যেহেতু পাইস্টেস্ট লগ বার্তা ক্যাপচার করে এবং কেবলমাত্র ব্যর্থ পরীক্ষার জন্য তাদের প্রদর্শন করে, আপনি সাধারণত কোনও লগিং অক্ষম করতে চান না। পরিবর্তে settings.pyপরীক্ষার জন্য পৃথক ফাইল ব্যবহার করুন (যেমন, test_settings.py), এবং এতে যুক্ত করুন:

LOGGING_CONFIG = None

এটি জ্যাঙ্গোকে লগিং সম্পূর্ণরূপে কনফিগার করতে এড়াতে বলে। LOGGINGসেটিং এড়িয়ে যাওয়া হবে এবং সেটিংস থেকে সরানো হতে পারে।

এই পদ্ধতির সাথে, আপনি পাস হওয়া পরীক্ষার জন্য কোনও লগিং পাবেন না এবং আপনি ব্যর্থ পরীক্ষার জন্য সমস্ত উপলব্ধ লগিং পাবেন ging

পরীক্ষাগুলি সেট আপ করা লগিং ব্যবহার করে চলবে pytest। এটি pytestসেটিংসে আপনার পছন্দ অনুসারে কনফিগার করা যেতে পারে (যেমন, tox.ini)। ডিবাগ স্তরের লগ বার্তাগুলি অন্তর্ভুক্ত করতে, log_level = DEBUG(বা সম্পর্কিত কমান্ড লাইন যুক্তি) ব্যবহার করুন।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.