python - تشغيل unittest مع بنية دليل الاختبار النموذجي




unit-testing (10)

يبدو أن بنية الدليل الشائعة جدًا حتى لوحدة بايثون بسيطة هي فصل اختبارات الوحدة إلى دليل test الخاص بها:

new_project/
    antigravity/
        antigravity.py
    test/
        test_antigravity.py
    setup.py
    etc.

على سبيل المثال رؤية هذا المشروع بايثون كيف .

سؤالي هو ببساطة ما هي الطريقة المعتادة لتشغيل الاختبارات؟ أظن أن هذا واضح للجميع باستثناء أنا ، لكن لا يمكنك فقط تشغيل python test_antigravity.py من دليل الاختبار حيث أن import antigravity سوف يفشل لأن الوحدة ليست في المسار.

أعلم أنه يمكنني تعديل PYTHONPATH والحيل الأخرى ذات الصلة بمسار البحث ، ولكن لا يمكنني تصديق أن هذه هي أبسط طريقة - فلا بأس إذا كنت مطورًا ولكن ليس من الواقعي أن تتوقع استخدام المستخدمين إذا كانوا يريدون فقط التحقق من الاختبارات عابرة.

البديل الآخر هو مجرد نسخ ملف الاختبار إلى الدليل الآخر ، ولكن يبدو غبيًا بعض الشيء ويفتقر إلى نقطة وجودهم في دليل منفصل للبدء به.

لذا ، إذا كنت قد قمت للتو بتنزيل المصدر لمشروعي الجديد ، فكيف تدير اختبارات الوحدة؟ أفضّل إجابة من شأنها أن تسمح لي بالقول لمستخدمي: "لتشغيل اختبارات الوحدة ، يجب إجراء X."


ما هي الطريقة المعتادة لتشغيل الاختبارات بالفعل

أنا استخدم Python 3.6.2

cd new_project

pytest test/test_antigravity.py

لتثبيت pytest : sudo pip install pytest

لم أقم بتعيين أي متغير مسار ولا يفشل استيراد بلدي مع نفس بنية المشروع "اختبار".

لقد علقت على هذه الأشياء: if __name__ == '__main__' مثل هذا:

test_antigravity.py

import antigravity

class TestAntigravity(unittest.TestCase):

    def test_something(self):

        # ... test stuff here


# if __name__ == '__main__':
# 
#     if __package__ is None:
# 
#         import something
#         sys.path.append(path.dirname(path.dirname(path.abspath(__file__))))
#         from .. import antigravity
# 
#     else:
# 
#         from .. import antigravity
# 
#     unittest.main()

أقوم بشكل عام بإنشاء برنامج نصي "تشغيل الاختبارات" في دليل المشروع (الدليل المشترك لكل من الدليل المصدر test ) الذي يحمّل مجموعة "كل الاختبارات" الخاصة بي. عادةً ما يكون هذا هو رمز معياري ، لذلك يمكنني إعادة استخدامه من مشروع إلى مشروع.

run_tests.py:

import unittest
import test.all_tests
testSuite = test.all_tests.create_test_suite()
text_runner = unittest.TextTestRunner().run(testSuite)

test / all_tests.py (من كيف يمكنني تشغيل جميع اختبارات وحدة بايثون في دليل؟ )

import glob
import unittest

def create_test_suite():
    test_file_strings = glob.glob('test/test_*.py')
    module_strings = ['test.'+str[5:len(str)-3] for str in test_file_strings]
    suites = [unittest.defaultTestLoader.loadTestsFromName(name) \
              for name in module_strings]
    testSuite = unittest.TestSuite(suites)
    return testSuite

باستخدام هذا الإعداد ، يمكنك بالفعل include antigravity في وحدات الاختبار الخاصة بك. الجانب السلبي هو أنك ستحتاج إلى المزيد من رمز الدعم لتنفيذ اختبار معين ... أنا فقط تشغيلها كل مرة.


إذا كنت تستخدم VS Code وتوجد اختباراتك على نفس مستوى مشروعك ، فعندئذٍ تعمل وتصحيحًا لا تعمل الشفرة خارج الإطار. ما يمكنك فعله هو تغيير ملف launch.json:

{
    "version": "0.2.0",
    "configurations": [
        {
            "name": "Python",
            "type": "python",
            "request": "launch",
            "stopOnEntry": false,
            "pythonPath": "${config:python.pythonPath}",
            "program": "${file}",
            "cwd": "${workspaceRoot}",
            "env": {},
            "envFile": "${workspaceRoot}/.env",
            "debugOptions": [
                "WaitOnAbnormalExit",
                "WaitOnNormalExit",
                "RedirectOutput"
            ]
        }    
    ]
}

الخط الرئيسي هنا هو envFile

"envFile": "${workspaceRoot}/.env",

في جذر المشروع الخاص بك إضافة ملف .env

داخل ملف .env الخاص بك إضافة مسار إلى جذر المشروع الخاص بك. هذا سوف يضيف مؤقتا

PYTHONPATH = C: \ ك \ PYTHON \ PROJECT \ ROOT_DIRECTORY

مسار لمشروعك وسوف تكون قادرًا على استخدام اختبارات وحدة التصحيح من VS Code


إن أبسط حل للمستخدمين هو تقديم نص برمجي قابل للتنفيذ ( runtests.py أو بعضًا من هذا القبيل) runtests.py بيئة الاختبار الضرورية ، بما في ذلك ، إذا لزم الأمر ، إضافة دليل مشروع الجذر إلى sys.path مؤقتًا. لا يتطلب ذلك من المستخدمين تعيين متغيرات بيئة ، شيء مثل هذا يعمل بشكل جيد في البرنامج النصي bootstrap:

import sys, os

sys.path.insert(0, os.path.dirname(__file__))

ثم يمكن أن تكون التعليمات الخاصة بك للمستخدمين بسيطة مثل "python runtests.py".

بالطبع ، إذا كان المسار الذي تحتاجه هو بالفعل os.path.dirname(__file__) ، فإنك لن تحتاج إلى إضافته إلى sys.path على الإطلاق ؛ يضع Python دومًا دليل البرنامج النصي الجاري تشغيله في بداية sys.path ، وبالتالي قد يكون تحديد موقع runtests.py الخاص بك في المكان الصحيح هو كل ما تحتاج إليه وذلك حسب بنية الدليل.

بالإضافة إلى ذلك ، فإن الوحدة غير المألوفة في Python 2.7+ (والتي يتم إعادة تثبيتها كـ unittest2 لـ Python 2.6 والإصدارات الأقدم) تمتلك الآن اكتشافًا مدمجًا ، لذا لم يعد الأنف ضروريًا إذا كنت تريد اكتشاف اختبار مؤتمت: يمكن أن تكون تعليمات المستخدم الخاصة بك بسيطة مثل "python -m unittest اكتشف".


الحل الأفضل في رأيي هو استخدام واجهة سطر الأوامر unittest الذي سيضيف الدليل إلى sys.path حتى لا تضطر إلى (القيام به في فئة TestLoader ).

على سبيل المثال لهيكل دليل مثل هذا:

new_project
├── antigravity.py
└── test_antigravity.py

يمكنك فقط تشغيل:

$ cd new_project
$ python -m unittest test_antigravity

بالنسبة إلى بنية الدليل مثل هيكلك:

new_project
├── antigravity
│   ├── __init__.py         # make it a package
│   └── antigravity.py
└── test
    ├── __init__.py         # also make test a package
    └── test_antigravity.py

وفي وحدات الاختبار داخل حزمة test ، يمكنك استيراد حزمة antigravity كالمعتاد:

# import the package
import antigravity

# import the antigravity module
from antigravity import antigravity

# or an object inside the antigravity module
from antigravity.antigravity import my_object

تشغيل وحدة اختبار واحدة:

لتشغيل وحدة اختبار واحدة ، في هذه الحالة ، test_antigravity.py :

$ cd new_project
$ python -m unittest test.test_antigravity

ما عليك سوى الرجوع إلى وحدة الاختبار بنفس طريقة استيرادها.

تشغيل حالة اختبار واحدة أو طريقة اختبار:

كما يمكنك تشغيل TestCase واحد أو طريقة اختبار واحدة:

$ python -m unittest test.test_antigravity.GravityTestCase
$ python -m unittest test.test_antigravity.GravityTestCase.test_method

تشغيل جميع الاختبارات:

يمكنك أيضًا استخدام اكتشاف الاختبار الذي سيكتشف جميع الاختبارات التي تجريها وتديرها ، ويجب أن تكون وحدات أو حزم تسمى test*.py (يمكن تغييرها باستخدام علامة -p, --pattern علم -p, --pattern ):

$ cd new_project
$ python -m unittest discover

سيؤدي هذا إلى تشغيل جميع test*.py داخل وحدات test .


فيما يلي هيكل مشروعي:

ProjectFolder:
 - project:
     - __init__.py
     - item.py
 - tests:
     - test_item.py

لقد وجدت أنه من الأفضل استيراد طريقة setUp ():

import unittest
import sys    

class ItemTest(unittest.TestCase):

    def setUp(self):
        sys.path.insert(0, "../project")
        from project import item
        # further setup using this import

    def test_item_props(self):
        # do my assertions

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

لقد لاحظت أنه في حالة تشغيل واجهة سطر الأوامر unittest من دليل "src" ، ثم تعمل الاستيراد بشكل صحيح دون تعديل.

python -m unittest discover -s ../test

إذا كنت تريد وضع ذلك في ملف دفعي في دليل المشروع ، فيمكنك القيام بذلك:

setlocal & cd src & python -m unittest discover -s ../test

من المقالة التي ربطتها بـ:

إنشاء ملف test_modulename.py ووضع اختبارات unittest فيه. بما أن الوحدات النمطية للاختبار موجودة في دليل منفصل عن التعليمة البرمجية الخاصة بك ، فقد تحتاج إلى إضافة دليل الوحدة النمطية الخاص بك إلى PYTHONPATH لتشغيلها:

$ cd /path/to/googlemaps

$ export PYTHONPATH=$PYTHONPATH:/path/to/googlemaps/googlemaps

$ python test/test_googlemaps.py

وأخيرًا ، هناك إطار اختبار وحدة أكثر شيوعًا لبيثون (إنه أمر مهم!) ، أنف. يساعد الأنف على تبسيط وإطالة إطار عمل unittest (يمكن ، على سبيل المثال ، العثور على رمز الاختبار الخاص بك تلقائيًا وإعداد PYTHONPATH لك) ، ولكنه لا يتم تضمينه مع توزيع بايثون القياسي.

ربما يجب عليك النظر في nose كما يوحي؟


يجب عليك حقا استخدام أداة نقطة.

استخدم pip install -e لتثبيت الحزمة الخاصة بك في وضع التطوير. هذه ممارسة جيدة للغاية.

في عنوان URL الموضح أدناه ، يتم إعطاء مخططين للمشروع الكلاسيكي (مع الاختبار) ، يمكنك اتباع أي منهما.

المرجع :


الحل / مثال لبايثون الوحدة unittest

بالنظر إلى هيكل المشروع التالي:

ProjectName
 ├── project_name
 |    ├── models
 |    |    └── thing_1.py
 |    └── __main__.py
 └── test
      ├── models
      |    └── test_thing_1.py
      └── __main__.py

يمكنك تشغيل المشروع من الدليل الجذر مع python project_name ، والذي يستدعي ProjectName/project_name/__main__.py .

لتشغيل اختباراتك مع python test ، فعليًا تشغيل ProjectName/test/__main__.py ، يلزمك إجراء ما يلي:

1) قم test/models دليل test/models الطراز الخاص بك إلى حزمة من خلال إضافة ملف __init__.py . هذا يجعل حالات الاختبار داخل الدليل الفرعي قابلة للوصول من دليل test الرئيسي.

# ProjectName/test/models/__init__.py

from .test_thing_1 import Thing1TestCase        

2) تعديل مسار النظام الخاص بك في test/__main__.py لتضمين الدليل project_name .

# ProjectName/test/__main__.py

import sys
import unittest

sys.path.append('../project_name')

loader = unittest.TestLoader()
testSuite = loader.discover('test')
testRunner = unittest.TextTestRunner(verbosity=2)
testRunner.run(testSuite)

يمكنك الآن استيراد الأشياء بنجاح من project_name في اختباراتك.

# ProjectName/test/models/test_thing_1.py    

import unittest
from project_name.models import Thing1  # this doesn't work without 'sys.path.append' per step 2 above

class Thing1TestCase(unittest.TestCase):

    def test_thing_1_init(self):
        thing_id = 'ABC'
        thing1 = Thing1(thing_id)
        self.assertEqual(thing_id, thing.id)




unit-testing