Получение unittest Python приводит к методу tearDown()

можно ли получить результаты теста (т. е. прошли ли все утверждения) в методе tearDown ()? Я запускаю сценарии Selenium, и я хотел бы сделать некоторые отчеты изнутри tearDown (), однако я не знаю, возможно ли это.

10 ответов


предостережение: у меня нет возможности дважды проверить следующую теорию на данный момент, находясь вдали от dev box. Так что это может быть выстрел в темноте.

возможно, вы могли бы проверить возвращаемое значение sys.exc_info() внутри вашего метода tearDown (), если он возвращает (None, None, None), вы знаете, что тестовый случай удался. В противном случае можно использовать возвращаемый Кортеж для опроса объекта исключения.

посмотреть sys.exc_info документация.

другой более явный подход написать декоратор метода, который вы могли бы шлепнуть на все ваши методы тестового случая, которые требуют этой специальной обработки. Этот декоратор может перехватывать исключения утверждений и на основе этого изменять некоторое состояние в self позволяет вашему методу демонтажа узнать, что случилось.

@assertion_tracker
def test_foo(self):
    # some test logic

если вы посмотрите на реализацию unittest.TestCase.run, вы можете видеть, что все результаты теста собираются в объекте результата (обычно unittest.TestResult instance) передается как аргумент. В "объект".

так что вы мало что можете сделать в unittest.TestCase.tearDown метод, если вы не беспощадно нарушаете элегантную развязку тестовых случаев и результатов тестов с чем-то вроде этого:

import unittest

class MyTest(unittest.TestCase):

    currentResult = None # holds last result object passed to run method

    def setUp(self):
        pass

    def tearDown(self):
        ok = self.currentResult.wasSuccessful()
        errors = self.currentResult.errors
        failures = self.currentResult.failures
        print ' All tests passed so far!' if ok else \
                ' %d errors and %d failures so far' % \
                (len(errors), len(failures))

    def run(self, result=None):
        self.currentResult = result # remember result for use in tearDown
        unittest.TestCase.run(self, result) # call superclass run method

    def test_onePlusOneEqualsTwo(self):
        self.assertTrue(1 + 1 == 2) # succeeds

    def test_onePlusOneEqualsThree(self):
        self.assertTrue(1 + 1 == 3) # fails

    def test_onePlusNoneIsNone(self):
        self.assertTrue(1 + None is None) # raises TypeError

if __name__ == '__main__':
    unittest.main()

EDIT: это работает для Python 2.6-3.3, (изменено для новых Питон Беллоу).


это решение для Python версии 2,7 до 3,6 (самая высокая текущая версия и разработка незадолго до 3.7-Альфа), без каких-либо декораторов или других изменений в любом коде до tearDown. Все работает в соответствии со встроенной классификацией результатов. Также пропустил тесты или expectedFailure распознаны верно. Он оценивает результат текущего теста, а не сводку всех тестов, пройденных до сих пор. Совместимый также с pytest.

import unittest

class MyTest(unittest.TestCase):
    def tearDown(self):
        if hasattr(self, '_outcome'):  # Python 3.4+
            result = self.defaultTestResult()  # these 2 methods have no side effects
            self._feedErrorsToResult(result, self._outcome.errors)
        else:  # Python 3.2 - 3.3 or 3.0 - 3.1 and 2.7
            result = getattr(self, '_outcomeForDoCleanups', self._resultForDoCleanups)
        error = self.list2reason(result.errors)
        failure = self.list2reason(result.failures)
        ok = not error and not failure

        # demo:   report short info immediately (not important)
        if not ok:
            typ, text = ('ERROR', error) if error else ('FAIL', failure)
            msg = [x for x in text.split('\n')[1:] if not x.startswith(' ')][0]
            print("\n%s: %s\n     %s" % (typ, self.id(), msg))

    def list2reason(self, exc_list):
        if exc_list and exc_list[-1][0] is self:
            return exc_list[-1][1]

    # DEMO tests
    def test_success(self):
        self.assertEqual(1, 1)

    def test_fail(self):
        self.assertEqual(2, 1)

    def test_error(self):
        self.assertEqual(1 / 0, 1)

комментарии: необходимо сообщить только об одном или нулевом исключении (ошибке или сбое), потому что до tearDown. Пакет unittest ожидает, что второе исключение может быть вызвано tearDown. Поэтому списки errors и failures может содержать только один или ноль элементов вместе до демонтажа. Строки после комментария "demo" сообщают короткий результат.

демо-выход: (не важно)

$ python3.5 -m unittest test

EF.
ERROR: test.MyTest.test_error
     ZeroDivisionError: division by zero
FAIL: test.MyTest.test_fail
     AssertionError: 2 != 1

==========================================================
... skipped usual output from unittest with tracebacks ...
...
Ran 3 tests in 0.002s

FAILED (failures=1, errors=1)

сравнение с другими решениями - (относительно истории фиксации исходного репозитория Python):

  • данное решение использует частная атрибут экземпляра TestCase, как многие иное решение, но я тщательно проверил все соответствующие коммиты в исходном репозитории Python эти три альтернативных имени охватывают историю кода начиная с Python 2.7-3.6.2 без любые пробелы. Это может быть проблемой после некоторого нового майора Выпуск Python, но он может быть четко распознан, пропущен и легко исправлен позже для нового Python. Преимущество в том, что ничего не изменяется до запуск tearDown, он никогда не должен нарушать тест и всю функциональность unittest поддерживается, работает с pytest, может работать со многими расширяющимися пакетами, но не с nosetest (не удивительно, потому что nosetest не совместим, например, с unittest.expectedFailure).

  • в решения с декораторы на методах теста потребителя или с подгонянным failureException ( mgilson, Павел Репин 2-й путь, kenorb) являются надежными против будущий Python версий, но если все должно работать полностью, они будут расти как snow ball с более поддерживаемыми исключениями и более реплицированными внутренними из unittest. Украшенные функции имеют менее читаемые tracebacks (еще больше уровней, добавленных одним декоратором), они сложнее для отладка и это unpleassant, если другой более важный декоратор иметь проблему. (Благодаря mgilson основная функциональность готова и известна проблемы могут быть исправлены.)

  • решение с modifired run способ и поймал result параметр

    • (scoffey) должно работать также для Python 2.6. Интерпретация результатов может быть улучшена до требования вопроса, но ничего не может работать в Python 3.4+, потому что result обновляется после вызова tearDown, никогда раньше.
    • Марк Григорьевич: (проверено с помощью Python 2.7, 3.2, 3.3, 3.4 и с nosetest)
  • решение exc_info() (Павел Репин 2-й путь) работает только с Python 2.

  • другие решения в основном похожи, но менее полные или с большим количеством ущерб.


объясняется исходным репозиторием Python
= Lib/unittest/case.py =
Python v 2.7-3.3

class TestCase(object):
    ...
    def run(self, result=None):
        ...
        self._outcomeForDoCleanups = result   # Python 3.2, 3.3
        # self._resultForDoCleanups = result  # Python 2.7
        #                                     # Python 2.6 - no result saved
        ...
        try:
            testMethod()
        except...   # many times for different exception classes
            result.add...(self, sys.exc_info())  # _addSkip, addError, addFailure
        ...
        try:
            self.tearDown()
        ...

Python V. 3.4-3.6

    def run(self, result=None):
        ...
        # outocome is a context manager to catch and collect different exceptions
        self._outcome = outcome  
        ...
        with outcome...(self):
            testMethod()
        ...
        with outcome...(self): 
            self.tearDown() 
        ... 
        self._feedErrorsToResult(result, outcome.errors)

Примечание (при чтении сообщения): одна из причин, почему результаты тестов так сильно отделены от испытаний утечки памяти профилактика. Каждая информация об исключении может получить доступ к кадрам состояния неудачного процесса, включая все локальные переменные. Если фрейм назначен локальной переменной в блоке кода, который также может завершиться ошибкой, то перекрестная память refence можно легко создать. Это не страшно, благодаря сборщику мусора, но свободная память может стать фрагментированной быстрее, чем если бы память была выпущена правильно. Вот почему информация об исключениях и трассировка очень скоро преобразуются в строки и почему временные объекты, такие как self._outcome инкапсулируются и никто в finally блок для предотвращения утечек памяти.


если вы используете Python2, вы можете использовать метод _resultForDoCleanups. Этот метод возвращает TextTestResult


следуя из ответа amatellanes, если вы находитесь на Python3.4, Вы не можете использовать _outcomeForDoCleanups. Вот что мне удалось взломать вместе:

def _test_has_failed(self):
    for method, error in self._outcome.errors:
        if error:
            return True
    return False

yucky, но, похоже, это работает.


Это зависит от того, какую отчетность вы хотели бы произвести.

в случае, если вы хотите сделать некоторые действия при сбое (например, создание скриншотов), вместо tearDown(), вы можете достичь этого, переопределив failureException.

например:

@property
def failureException(self):
    class MyFailureException(AssertionError):
        def __init__(self_, *args, **kwargs):
            screenshot_dir = 'reports/screenshots'
            if not os.path.exists(screenshot_dir):
                os.makedirs(screenshot_dir)
            self.driver.save_screenshot('{0}/{1}.png'.format(screenshot_dir, self.id()))
            return super(MyFailureException, self_).__init__(*args, **kwargs)
    MyFailureException.__name__ = AssertionError.__name__
    return MyFailureException

вот решение для тех из нас, кто неудобно использовать решения, которые полагаются на unittest внутренние:

во-первых, мы создаем декоратор, который будет установлен флаг TestCase экземпляр, чтобы определить, был ли тестовый случай неудачным или прошел:

import unittest
import functools

def _tag_error(func):
    """Decorates a unittest test function to add failure information to the TestCase."""

    @functools.wraps(func)
    def decorator(self, *args, **kwargs):
        """Add failure information to `self` when `func` raises an exception."""
        self.test_failed = False
        try:
            func(self, *args, **kwargs)
        except unittest.SkipTest:
            raise
        except Exception:  # pylint: disable=broad-except
            self.test_failed = True
            raise  # re-raise the error with the original traceback.

    return decorator

этот декоратор на самом деле довольно прост. Он полагается на то, что unittest обнаруживает неудачные тесты через исключения. Насколько мне известно, единственное специальные исключением, которое необходимо обработать, является unittest.SkipTest (что не указывает на провал теста). Все остальные исключения указывают на провалы тестов, поэтому мы отмечаем их как таковые, когда они всплывают к нам.

теперь мы можем использовать этот декоратор напрямую:

class MyTest(unittest.TestCase):
    test_failed = False

    def tearDown(self):
        super(MyTest, self).tearDown()
        print(self.test_failed)

    @_tag_error
    def test_something(self):
        self.fail('Bummer')

это будет очень раздражать писать этот декоратор все время. Есть ли способ упростить? Да есть!* мы можем написать метакласс для обработки применения декоратора для мы:

class _TestFailedMeta(type):
    """Metaclass to decorate test methods to append error information to the TestCase instance."""
    def __new__(cls, name, bases, dct):
        for name, prop in dct.items():
            # assume that TestLoader.testMethodPrefix hasn't been messed with -- otherwise, we're hosed.
            if name.startswith('test') and callable(prop):
                dct[name] = _tag_error(prop)

        return super(_TestFailedMeta, cls).__new__(cls, name, bases, dct)

теперь мы применяем это к нашей базе TestCase подкласс, и мы все готовы:

import six  # For python2.x/3.x compatibility

class BaseTestCase(six.with_metaclass(_TestFailedMeta, unittest.TestCase)):
    """Base class for all our other tests.

    We don't really need this, but it demonstrates that the
    metaclass gets applied to all subclasses too.
    """


class MyTest(BaseTestCase):

    def tearDown(self):
        super(MyTest, self).tearDown()
        print(self.test_failed)

    def test_something(self):
        self.fail('Bummer')

вероятно, есть несколько случаев, которые это не обрабатывает должным образом. Например, он неправильно обнаруживает сбой субтестам или ожидаемые ошибки. Я был бы заинтересован в других режимах отказа этого, поэтому, если вы найдете случай, который я не обрабатываю должным образом, Дайте мне знать в комментариях, и я посмотрю он.


*если бы не было более простого способа, я бы не сделал _tag_error собственная функция ;-)


Python 2.7.

вы также можете получить результат после unittest.main():

t = unittest.main(exit=False)
print t.result

или используйте suite:

suite.addTests(tests)
result = unittest.result.TestResult()
suite.run(result)
print result

имя текущего теста можно получить с помощью unittest.Тест-кейс.id () метод. Так что в tearDown вы можете проверить себя.id().

пример показывает, как:

  • найти, если текущий тест имеет ошибку или сбой в списке ошибок или сбоев
  • печать тестового идентификатора с пропуском или сбоем или исключением

проверенный пример здесь работает с хорошим примером @scoffey.

def tearDown(self):
    result = "PASS"
    #### find and show result for current test
    # I did not find any nicer/neater way of comparing self.id() with test id stored in errors or failures lists :-7
    id = str(self.id()).split('.')[-1]
    # id() e.g. tup[0]:<__main__.MyTest testMethod=test_onePlusNoneIsNone>
    #           str(tup[0]):"test_onePlusOneEqualsThree (__main__.MyTest)"
    #           str(self.id()) = __main__.MyTest.test_onePlusNoneIsNone
    for tup in self.currentResult.failures:
        if str(tup[0]).startswith(id):
            print ' test %s failure:%s' % (self.id(), tup[1])
            ## DO TEST FAIL ACTION HERE
            result = "FAIL"
    for tup in self.currentResult.errors:
        if str(tup[0]).startswith(id):
            print ' test %s error:%s' % (self.id(), tup[1])
            ## DO TEST EXCEPTION ACTION HERE
            result = "EXCEPTION"

    print "Test:%s Result:%s" % (self.id(), result)

пример:

python run_scripts/tut2.py 2>&1 
E test __main__.MyTest.test_onePlusNoneIsNone error:Traceback (most recent call last):
  File "run_scripts/tut2.py", line 80, in test_onePlusNoneIsNone
    self.assertTrue(1 + None is None) # raises TypeError
TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'

Test:__main__.MyTest.test_onePlusNoneIsNone Result:EXCEPTION
F test __main__.MyTest.test_onePlusOneEqualsThree failure:Traceback (most recent call last):
  File "run_scripts/tut2.py", line 77, in test_onePlusOneEqualsThree
    self.assertTrue(1 + 1 == 3) # fails
AssertionError: False is not true

Test:__main__.MyTest.test_onePlusOneEqualsThree Result:FAIL
Test:__main__.MyTest.test_onePlusOneEqualsTwo Result:PASS
.
======================================================================
ERROR: test_onePlusNoneIsNone (__main__.MyTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "run_scripts/tut2.py", line 80, in test_onePlusNoneIsNone
    self.assertTrue(1 + None is None) # raises TypeError
TypeError: unsupported operand type(s) for +: 'int' and 'NoneType'

======================================================================
FAIL: test_onePlusOneEqualsThree (__main__.MyTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "run_scripts/tut2.py", line 77, in test_onePlusOneEqualsThree
     self.assertTrue(1 + 1 == 3) # fails
AssertionError: False is not true

----------------------------------------------------------------------
Ran 3 tests in 0.001s

FAILED (failures=1, errors=1)

вдохновленный scoffey это, я решил взять mercilessnes на следующий уровень, и придумали следующее.

он работает как в vanilla unittest, так и при запуске через nosetests, а также работает в версиях Python 2.7, 3.2, 3.3 и 3.4 (я специально не тестировал 3.0, 3.1 или 3.5, так как у меня их нет на данный момент, но если я прочитаю исходный код правильно, он должен работать в 3.5 а ну):

#! /usr/bin/env python

from __future__ import unicode_literals
import logging
import os
import sys
import unittest


# Log file to see squawks during testing
formatter = logging.Formatter(fmt='%(levelname)-8s %(name)s: %(message)s')
log_file = os.path.splitext(os.path.abspath(__file__))[0] + '.log'
handler = logging.FileHandler(log_file)
handler.setFormatter(formatter)
logging.root.addHandler(handler)
logging.root.setLevel(logging.DEBUG)
log = logging.getLogger(__name__)


PY = tuple(sys.version_info)[:3]


class SmartTestCase(unittest.TestCase):

    """Knows its state (pass/fail/error) by the time its tearDown is called."""

    def run(self, result):
        # Store the result on the class so tearDown can behave appropriately
        self.result = result.result if hasattr(result, 'result') else result
        if PY >= (3, 4, 0):
            self._feedErrorsToResultEarly = self._feedErrorsToResult
            self._feedErrorsToResult = lambda *args, **kwargs: None  # no-op
        super(SmartTestCase, self).run(result)

    @property
    def errored(self):
        if (3, 0, 0) <= PY < (3, 4, 0):
            return bool(self._outcomeForDoCleanups.errors)
        return self.id() in [case.id() for case, _ in self.result.errors]

    @property
    def failed(self):
        if (3, 0, 0) <= PY < (3, 4, 0):
            return bool(self._outcomeForDoCleanups.failures)
        return self.id() in [case.id() for case, _ in self.result.failures]

    @property
    def passed(self):
        return not (self.errored or self.failed)

    def tearDown(self):
        if PY >= (3, 4, 0):
            self._feedErrorsToResultEarly(self.result, self._outcome.errors)


class TestClass(SmartTestCase):

    def test_1(self):
        self.assertTrue(True)

    def test_2(self):
        self.assertFalse(True)

    def test_3(self):
        self.assertFalse(False)

    def test_4(self):
        self.assertTrue(False)

    def test_5(self):
        self.assertHerp('Derp')

    def tearDown(self):
        super(TestClass, self).tearDown()
        log.critical('---- RUNNING {} ... -----'.format(self.id()))
        if self.errored:
            log.critical('----- ERRORED -----')
        elif self.failed:
            log.critical('----- FAILED -----')
        else:
            log.critical('----- PASSED -----')


if __name__ == '__main__':
    unittest.main()

при запуске с unittest:

$ ./test.py -v
test_1 (__main__.TestClass) ... ok
test_2 (__main__.TestClass) ... FAIL
test_3 (__main__.TestClass) ... ok
test_4 (__main__.TestClass) ... FAIL
test_5 (__main__.TestClass) ... ERROR
[…]

$ cat ./test.log
CRITICAL __main__: ---- RUNNING __main__.TestClass.test_1 ... -----
CRITICAL __main__: ----- PASSED -----
CRITICAL __main__: ---- RUNNING __main__.TestClass.test_2 ... -----
CRITICAL __main__: ----- FAILED -----
CRITICAL __main__: ---- RUNNING __main__.TestClass.test_3 ... -----
CRITICAL __main__: ----- PASSED -----
CRITICAL __main__: ---- RUNNING __main__.TestClass.test_4 ... -----
CRITICAL __main__: ----- FAILED -----
CRITICAL __main__: ---- RUNNING __main__.TestClass.test_5 ... -----
CRITICAL __main__: ----- ERRORED -----

при запуске с nosetests:

$ nosetests ./test.py -v
test_1 (test.TestClass) ... ok
test_2 (test.TestClass) ... FAIL
test_3 (test.TestClass) ... ok
test_4 (test.TestClass) ... FAIL
test_5 (test.TestClass) ... ERROR

$ cat ./test.log
CRITICAL test: ---- RUNNING test.TestClass.test_1 ... -----
CRITICAL test: ----- PASSED -----
CRITICAL test: ---- RUNNING test.TestClass.test_2 ... -----
CRITICAL test: ----- FAILED -----
CRITICAL test: ---- RUNNING test.TestClass.test_3 ... -----
CRITICAL test: ----- PASSED -----
CRITICAL test: ---- RUNNING test.TestClass.test_4 ... -----
CRITICAL test: ----- FAILED -----
CRITICAL test: ---- RUNNING test.TestClass.test_5 ... -----
CRITICAL test: ----- ERRORED -----

фон

я started С этого:

class SmartTestCase(unittest.TestCase):

    """Knows its state (pass/fail/error) by the time its tearDown is called."""

    def run(self, result):
        # Store the result on the class so tearDown can behave appropriately
        self.result = result.result if hasattr(result, 'result') else result
        super(SmartTestCase, self).run(result)

    @property
    def errored(self):
        return self.id() in [case.id() for case, _ in self.result.errors]

    @property
    def failed(self):
        return self.id() in [case.id() for case, _ in self.result.failures]

    @property
    def passed(self):
        return not (self.errored or self.failed)

однако это работает только в Python 2. В Python 3, вплоть до 3.3, поток управления, похоже, немного изменился: unittest packageпроцессы результаты после вызов каждого теста tearDown() этот способ... поведение может быть подтверждено, если мы просто добавим дополнительную строку (или шесть) в наш тестовый класс:

@@ -63,6 +63,12 @@
             log.critical('----- FAILED -----')
         else:
             log.critical('----- PASSED -----')
+        log.warning(
+            'ERRORS THUS FAR:\n'
+            + '\n'.join(tc.id() for tc, _ in self.result.errors))
+        log.warning(
+            'FAILURES THUS FAR:\n'
+            + '\n'.join(tc.id() for tc, _ in self.result.failures))


 if __name__ == '__main__':

затем просто повторно запустите тесты:

$ python3.3 ./test.py -v
test_1 (__main__.TestClass) ... ok
test_2 (__main__.TestClass) ... FAIL
test_3 (__main__.TestClass) ... ok
test_4 (__main__.TestClass) ... FAIL
test_5 (__main__.TestClass) ... ERROR
[…]

...и вы увидите, что вы получите как результат:

CRITICAL __main__: ---- RUNNING __main__.TestClass.test_1 ... -----
CRITICAL __main__: ----- PASSED -----
WARNING  __main__: ERRORS THUS FAR:

WARNING  __main__: FAILURES THUS FAR:

CRITICAL __main__: ---- RUNNING __main__.TestClass.test_2 ... -----
CRITICAL __main__: ----- PASSED -----
WARNING  __main__: ERRORS THUS FAR:

WARNING  __main__: FAILURES THUS FAR:

CRITICAL __main__: ---- RUNNING __main__.TestClass.test_3 ... -----
CRITICAL __main__: ----- PASSED -----
WARNING  __main__: ERRORS THUS FAR:

WARNING  __main__: FAILURES THUS FAR:
__main__.TestClass.test_2
CRITICAL __main__: ---- RUNNING __main__.TestClass.test_4 ... -----
CRITICAL __main__: ----- PASSED -----
WARNING  __main__: ERRORS THUS FAR:

WARNING  __main__: FAILURES THUS FAR:
__main__.TestClass.test_2
CRITICAL __main__: ---- RUNNING __main__.TestClass.test_5 ... -----
CRITICAL __main__: ----- PASSED -----
WARNING  __main__: ERRORS THUS FAR:

WARNING  __main__: FAILURES THUS FAR:
__main__.TestClass.test_2
__main__.TestClass.test_4

теперь сравните вышеизложенное с выводом Python 2:

CRITICAL __main__: ---- RUNNING __main__.TestClass.test_1 ... -----
CRITICAL __main__: ----- PASSED -----
WARNING  __main__: ERRORS THUS FAR:

WARNING  __main__: FAILURES THUS FAR:

CRITICAL __main__: ---- RUNNING __main__.TestClass.test_2 ... -----
CRITICAL __main__: ----- FAILED -----
WARNING  __main__: ERRORS THUS FAR:

WARNING  __main__: FAILURES THUS FAR:
__main__.TestClass.test_2
CRITICAL __main__: ---- RUNNING __main__.TestClass.test_3 ... -----
CRITICAL __main__: ----- PASSED -----
WARNING  __main__: ERRORS THUS FAR:

WARNING  __main__: FAILURES THUS FAR:
__main__.TestClass.test_2
CRITICAL __main__: ---- RUNNING __main__.TestClass.test_4 ... -----
CRITICAL __main__: ----- FAILED -----
WARNING  __main__: ERRORS THUS FAR:

WARNING  __main__: FAILURES THUS FAR:
__main__.TestClass.test_2
__main__.TestClass.test_4
CRITICAL __main__: ---- RUNNING __main__.TestClass.test_5 ... -----
CRITICAL __main__: ----- ERRORED -----
WARNING  __main__: ERRORS THUS FAR:
__main__.TestClass.test_5
WARNING  __main__: FAILURES THUS FAR:
__main__.TestClass.test_2
__main__.TestClass.test_4

поскольку Python 3 обрабатывает ошибки / сбои после тест снесен, мы не можем легко вывести результат теста с помощью result.errors или result.failures в каждом случае. (Я думаю, что, вероятно, имеет смысл архитектурно обрабатывать результаты теста после срывая его, однако, это тут сделайте совершенно допустимый вариант использования следующей другой процедуры завершения теста в зависимости от состояния pass/fail теста немного сложнее встретить...)

поэтому, вместо того, чтобы полагаться на общую