เรียกใช้ไม่ได้ด้วยโครงสร้างไดเรกทอรีทดสอบทั่วไป


701

โครงสร้างไดเรกทอรีทั่วไปมากสำหรับแม้แต่โมดูล Python ที่เรียบง่ายดูเหมือนว่าจะแยกการทดสอบหน่วยออกเป็นtestไดเรกทอรีของตนเอง:

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

เช่นดูโครงการ Python นี้อย่างไร

คำถามของฉันเป็นเพียงวิธีปกติของการทดสอบจริง ๆ คืออะไร? ฉันสงสัยว่านี่เป็นสิ่งที่ชัดเจนสำหรับทุกคนยกเว้นฉัน แต่คุณไม่สามารถเรียกใช้python test_antigravity.pyจากไดเรกทอรีทดสอบได้เพราะมันimport antigravityจะล้มเหลวเนื่องจากโมดูลไม่ได้อยู่ในเส้นทาง

ฉันรู้ว่าฉันสามารถแก้ไข PYTHONPATH และลูกเล่นการค้นหาอื่น ๆ ที่เกี่ยวข้องกับเส้นทางได้ แต่ฉันไม่อยากเชื่อว่านั่นเป็นวิธีที่ง่ายที่สุด - ก็ดีถ้าคุณเป็นนักพัฒนา แต่ไม่เป็นจริงที่จะคาดหวังให้ผู้ใช้ของคุณใช้งาน ที่ผ่านไป

อีกทางเลือกหนึ่งคือการคัดลอกไฟล์ทดสอบไปยังไดเรกทอรีอื่น แต่ดูเหมือนจะเป็นบิตและขาดจุดในการมีไฟล์ในไดเรกทอรีแยกกันเพื่อเริ่มต้น

ดังนั้นหากคุณเพิ่งดาวน์โหลดซอร์สไปยังโครงการใหม่ของฉันคุณจะทดสอบหน่วยได้อย่างไร ฉันต้องการคำตอบที่จะให้ฉันพูดกับผู้ใช้ของฉัน: "การเรียกใช้การทดสอบหน่วยทำ X"


5
@EMP โซลูชันที่เหมาะสมเมื่อคุณต้องการตั้งค่าพา ธ การค้นหาคือ ... กำหนดพา ธ การค้นหา คุณคาดหวังวิธีแก้ปัญหาแบบใด
Carl Meyer

7
@CarlMeyer อีกวิธีที่ดีกว่าคือการใช้unittestอินเตอร์เฟสบรรทัดคำสั่งดังที่อธิบายไว้ในคำตอบของฉันด้านล่างดังนั้นคุณไม่จำเป็นต้องเพิ่มไดเรกทอรีไปยังเส้นทาง
Pierre

13
กันที่นี่ ฉันเพิ่งเริ่มเขียนการทดสอบหน่วยแรกของฉันในโครงการ Python ขนาดเล็กและใช้เวลาหลายวันพยายามที่จะให้เหตุผลกับความจริงที่ว่าฉันไม่สามารถทำการทดสอบได้อย่างง่ายดายในขณะที่รักษาแหล่งที่มาของฉันไว้ในไดเรกทอรี src และการทดสอบในไดเรกทอรีทดสอบ ดูเหมือนกับกรอบการทดสอบใด ๆ ที่มีอยู่ ในที่สุดฉันจะยอมรับสิ่งต่าง ๆ คิดหาวิธี; แต่นี่เป็นการแนะนำที่น่าผิดหวังอย่างมาก (และฉันเป็นทหารผ่านศึกทดสอบหน่วยนอก Python)
Ates Goral

คำตอบ:


657

ทางออกที่ดีที่สุดในความคิดของฉันคือการใช้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ตั้งค่าสถานะ):

$ cd new_project
$ python -m unittest discover
$ # Also works without discover for Python 3
$ # as suggested by @Burrito in the comments
$ python -m unittest

สิ่งนี้จะเรียกใช้test*.pyโมดูลทั้งหมดที่อยู่ในtestแพ็คเกจ


53
python -m unittest discoverจะค้นหาและเรียกใช้การทดสอบในไดเรกทอรีถ้าพวกเขาจะถูกตั้งชื่อtest test*.pyหากคุณตั้งชื่อไดเรกทอรีย่อยtestsให้ใช้python -m unittest discover -s testsและถ้าคุณตั้งชื่อไฟล์ทดสอบantigravity_test.pyให้ใช้python -m unittest discover -s tests -p '*test.py' ชื่อไฟล์สามารถใช้เครื่องหมายขีดล่าง แต่ไม่ขีดกลาง
Mike3d0g

10
สิ่งนี้ล้มเหลวสำหรับฉันใน Python 3 ที่มีข้อผิดพลาดImportError: No module named 'test.test_antigravity'เนื่องจากความขัดแย้งกับโมดูลย่อยการทดสอบของไลบรารี unittest อาจผู้เชี่ยวชาญสามารถยืนยันและเปลี่ยนชื่อไดเรกทอรีย่อยคำตอบเป็น 'ทดสอบ' (พหูพจน์)
expz

10
ฉันtest_antigravity.pyยังคงโยนข้อผิดพลาดในการนำเข้าสำหรับทั้งimport antigravityและfrom antigravity import antigravityเช่นกัน ฉันมีทั้ง__init_.pyไฟล์และฉันกำลังโทรpython3 -m unittest discoverจากnew projectไดเรกทอรี มีอะไรผิดปกติอีกไหม?
imrek

20
ไฟล์test/__init__.pyเป็นสิ่งสำคัญที่นี่แม้ว่าจะว่างเปล่า
Francois

3
@ Mike3d0g ไม่แน่ใจว่าคุณตั้งใจจะบอกเป็นนัยว่าชื่อไดเรกทอรีtestนั้นพิเศษ ... แต่เพียงเพื่อบันทึกมันไม่ได้ : P python -m unittest discoverทำงานร่วมกับไฟล์ในการทดสอบเพียงเป็นtests/ test/
ไรอัน

49

ทางออกที่ง่ายที่สุดสำหรับผู้ใช้ของคุณคือจัดเตรียมสคริปต์ที่สามารถใช้งานได้ ( 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ในตำแหน่งที่ถูกต้องอาจเป็นสิ่งที่จำเป็น

นอกจากนี้โมดูล unittest ใน Python 2.7+ (ซึ่งถูก backported เป็นunittest2สำหรับ Python 2.6 และก่อนหน้านี้) มีการทดสอบการค้นพบในตัวดังนั้นจมูกจึงไม่จำเป็นอีกต่อไปหากคุณต้องการการค้นหาทดสอบอัตโนมัติ: คำแนะนำผู้ใช้ของคุณนั้นเรียบง่ายpython -m unittest discover.


ฉันทำการทดสอบบางอย่างในโฟลเดอร์ย่อยเหมือน "Major Major" พวกเขาสามารถรันด้วย python -m unittest ที่ค้นพบ แต่ฉันจะเลือกให้เรียกใช้หนึ่งในนั้นได้อย่างไร ถ้าฉันรัน python -m unittest tests / testxxxxx มันจะล้มเหลวสำหรับปัญหาเกี่ยวกับเส้นทาง ตั้งแต่โหมด dicovery แก้ปัญหาทุกอย่างผมจะคาดหวังว่ามีเคล็ดลับอื่นในการแก้ปัญหาเส้นทางโดยไม่ต้อง Handcoding แก้ไขเส้นทางที่คุณแนะนำในจุดแรก
เฟรเดริก Bazin

2
@FredericBazin อย่าใช้การค้นพบหากคุณต้องการทดสอบหรือไฟล์ทดสอบเพียงอย่างเดียวเพียงแค่ตั้งชื่อโมดูลที่คุณต้องการเรียกใช้ หากคุณตั้งชื่อมันว่าเป็นโมดูลประเส้นทาง (แทนที่จะเป็นเส้นทางไฟล์) ก็สามารถหาเส้นทางการค้นหาได้อย่างถูกต้อง ดูคำตอบของ Peter สำหรับรายละเอียดเพิ่มเติม
คาร์ลเมเยอร์

python -m pdb tests\test_antigravity.pyสับนี้เป็นประโยชน์ในสถานการณ์ที่ผมต้องทำงานบางอย่างเช่น ภายใน pdb ฉันดำเนินการsys.path.insert(0, "antigravity")ซึ่งอนุญาตให้ใช้คำสั่งนำเข้าเพื่อแก้ไขราวกับว่าฉันกำลังเรียกใช้โมดูล
ixe013

23

โดยทั่วไปฉันสร้างสคริปต์ "ทดสอบการทำงาน" ในไดเรกทอรีโครงการ (สคริปต์ที่ใช้ร่วมกันทั้งในไดเรกทอรีต้นฉบับและtest) ที่โหลดชุด "All Tests" ของฉัน โดยทั่วไปจะเป็นรหัสสำเร็จรูปดังนั้นฉันสามารถนำมาใช้ใหม่จากโครงการหนึ่งไปอีกโครงการหนึ่ง

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 (จากฉันจะรันการทดสอบหน่วย Python ทั้งหมดในไดเรกทอรีได้อย่างไร )

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ในโมดูลทดสอบของคุณ ข้อเสียคือคุณจะต้องมีรหัสสนับสนุนเพิ่มเติมเพื่อดำเนินการทดสอบโดยเฉพาะ ... ฉันแค่เรียกใช้มันทุกครั้ง


1
ฉันยังอยากสคริปต์ในไดเรกทอรีโครงการและพบว่าเป็นวิธีทำความสะอาดจำนวนมากที่จะทำมัน แนะนำเป็นอย่างยิ่ง run tests
z33k

18

จากบทความที่คุณเชื่อมโยงกับ:

สร้างไฟล์ test_modulename.py และทำการทดสอบที่ไม่สำคัญที่สุด เนื่องจากโมดูลทดสอบอยู่ในไดเรกทอรีแยกต่างหากจากรหัสของคุณคุณอาจต้องเพิ่มไดเรกทอรีหลักของโมดูลของคุณไปยัง PYTHONPATH ของคุณเพื่อเรียกใช้:

$ cd /path/to/googlemaps

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

$ python test/test_googlemaps.py

ในที่สุดมีกรอบการทดสอบหน่วยที่นิยมอีกหนึ่งสำหรับ Python (มันสำคัญมาก!) จมูก จมูกช่วยให้ง่ายขึ้นและขยายกรอบงานที่เล็กที่สุดในตัว (เช่นสามารถค้นหารหัสทดสอบของคุณโดยอัตโนมัติและตั้งค่า PYTHONPATH ให้กับคุณ) แต่ไม่รวมอยู่ในการแจกจ่าย Python มาตรฐาน

บางทีคุณควรมองจมูกตามที่แนะนำ?


3
ใช่มันใช้งานได้ (สำหรับฉัน) แต่ฉันขอคำแนะนำที่ง่ายที่สุดที่ฉันสามารถให้ผู้ใช้กับโมดูลของฉันเพื่อให้พวกเขาทำการทดสอบ การปรับเปลี่ยนเส้นทางอาจเป็นไปได้ แต่ฉันกำลังหาอะไรที่ตรงไปตรงมามากกว่า
เมเจอร์เมเจอร์

4
ดังนั้นเส้นทางไพ ธ อนของคุณจะเป็นอย่างไรหลังจากคุณทำงานกับโครงการกว่าร้อยโครงการ ฉันควรเข้าไปข้างในและทำความสะอาดเส้นทางของฉันด้วยตนเองหรือไม่? ถ้านี่คือการออกแบบที่น่ารังเกียจ!
jeremyjjbrown

11

ฉันมีปัญหาเดียวกันกับโฟลเดอร์การทดสอบหน่วยแยกต่างหาก จากคำแนะนำที่กล่าวถึงฉันเพิ่มเส้นทางของแหล่งข้อมูลที่แน่นอนsys.pathที่จะ

ประโยชน์ของโซลูชันต่อไปนี้คือสามารถเรียกใช้ไฟล์test/test_yourmodule.pyโดยไม่เปลี่ยนแปลงในตอนแรกลงในไดเรกทอรีทดสอบ:

import sys, os
testdir = os.path.dirname(__file__)
srcdir = '../antigravity'
sys.path.insert(0, os.path.abspath(os.path.join(testdir, srcdir)))

import antigravity
import unittest

9

ถ้าคุณเรียกใช้ "python setup.py พัฒนา" แพคเกจจะอยู่ในเส้นทาง แต่คุณอาจไม่ต้องการทำเช่นนั้นเพราะคุณสามารถติดตั้งการติดตั้งงูหลามระบบของคุณซึ่งเป็นสาเหตุที่มีเครื่องมือเช่นvirtualenvและbuildoutอยู่


7

ทางออก / ตัวอย่างสำหรับโมดูล Python unittest

รับโครงสร้างโครงการดังต่อไปนี้:

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

คุณสามารถเรียกใช้โครงการของคุณจากไดเรกทอรีรากด้วยซึ่งการโทรpython project_nameProjectName/project_name/__main__.py


ในการรันการทดสอบด้วยการpython testรันอย่างมีประสิทธิภาพProjectName/test/__main__.pyคุณต้องทำสิ่งต่อไปนี้:

1)เปลี่ยน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)

5

ใช้setup.py developเพื่อทำให้ไดเรกทอรีทำงานของคุณเป็นส่วนหนึ่งของสภาพแวดล้อม Python ที่ติดตั้งแล้วรันการทดสอบ


นี้ได้รับฉันและตัวเลือกนี้ไม่ได้กล่าวถึงถ้าฉันขอinvalid command 'develop' setup.py --help-commandsจำเป็นต้องมีบางสิ่งบางอย่างในsetup.pyตัวเองเพื่อให้ทำงานได้หรือไม่
เมเจอร์เมเจอร์

มันก็โอเค - ปัญหาคือฉันหายไปimport setuptoolsจากsetup.pyไฟล์ของฉัน แต่ฉันเดาว่ามันจะไปเพื่อแสดงให้เห็นว่านี่จะไม่ทำงานตลอดเวลาสำหรับโมดูลของคนอื่น
เมเจอร์เมเจอร์

1
หากคุณมีpipคุณสามารถใช้สิ่งนั้นเพื่อติดตั้งแพ็กเกจของคุณในโหมด "แก้ไขได้" : pip install -e .เช่นนี้จะเพิ่มแพ็คเกจไปยังสภาพแวดล้อม Python โดยไม่ต้องคัดลอกแหล่งที่มา
Eric Smith เมื่อ

pip install -e .เป็นสิ่งเดียวกับที่python setup.py developมันเป็นแค่ monkeypatches ของคุณที่setup.pyจะใช้ setuptools แม้ว่ามันจะไม่ได้จริงดังนั้นมันก็ใช้ได้ทั้งสองทาง
คาร์ลเมเยอร์

5

หากคุณใช้รหัส VS และการทดสอบของคุณอยู่ในระดับเดียวกับโครงการของคุณจากนั้นเรียกใช้และแก้ไขข้อบกพร่องของรหัสของคุณจะไม่ทำงานนอกกรอบ สิ่งที่คุณสามารถทำได้คือเปลี่ยนไฟล์ 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 \ โครงการ \ ROOT_DIRECTORY

พา ธ ไปยังโครงการของคุณและคุณจะสามารถใช้การทดสอบหน่วยดีบั๊กจากรหัส VS


5

ฉันสังเกตเห็นว่าถ้าคุณเรียกใช้อินเตอร์เฟสบรรทัดคำสั่งที่ไม่ได้มาจากไดเรกทอรี "src" ของคุณแสดงว่าการนำเข้าทำงานอย่างถูกต้องโดยไม่มีการดัดแปลง

python -m unittest discover -s ../test

ถ้าคุณต้องการที่จะวางไว้ในไฟล์แบทช์ในไดเรกทอรีโครงการของคุณคุณสามารถทำได้:

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

5

ฉันมีปัญหาเดียวกันมานานแล้ว สิ่งที่ฉันเลือกล่าสุดคือโครงสร้างไดเรกทอรีต่อไปนี้:

project_path
├── Makefile
├── src
   ├── script_1.py
   ├── script_2.py
   └── script_3.py
└── tests
    ├── __init__.py
    ├── test_script_1.py
    ├── test_script_2.py
    └── test_script_3.py

และใน__init__.pyสคริปต์ของโฟลเดอร์ทดสอบฉันเขียนสิ่งต่อไปนี้:

import os
import sys
PROJECT_PATH = os.getcwd()
SOURCE_PATH = os.path.join(
    PROJECT_PATH,"src"
)
sys.path.append(SOURCE_PATH)

สำคัญอย่างยิ่งสำหรับการแชร์โปรเจ็กต์คือ Makefile เนื่องจากบังคับให้รันสคริปต์อย่างถูกต้อง นี่คือคำสั่งที่ฉันใส่ใน Makefile:

run_tests:
    python -m unittest discover .

Makefile มีความสำคัญไม่เพียงเพราะคำสั่งที่รัน แต่ยังเป็นเพราะสิ่งที่มันเรียกใช้ หากคุณต้องการทดสอบในซีดีและทำpython -m unittest discover .มันจะไม่ทำงานเพราะinitสคริปต์ใน unit_tests เรียก os.getcwd () ซึ่งจะชี้ไปที่เส้นทางสัมบูรณ์ที่ไม่ถูกต้อง (ซึ่งจะผนวกเข้ากับ sys.path และคุณจะหายไป โฟลเดอร์ต้นทางของคุณ) สคริปต์จะทำงานเนื่องจากค้นพบการทดสอบทั้งหมด แต่ไม่สามารถทำงานได้อย่างถูกต้อง ดังนั้น Makefile จึงอยู่ที่นั่นเพื่อหลีกเลี่ยงการจำปัญหานี้

ฉันชอบวิธีนี้มากเพราะฉันไม่ต้องแตะโฟลเดอร์ src ของฉันทดสอบหน่วยหรือตัวแปรสภาพแวดล้อมของฉันและทุกอย่างทำงานได้อย่างราบรื่น

แจ้งให้เราทราบหากพวกคุณชอบมัน

หวังว่าจะช่วย


4

ต่อไปนี้เป็นโครงสร้างโครงการของฉัน:

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

4

เป็นวิธีปกติในการเรียกใช้การทดสอบอะไร

ฉันใช้ 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()

4

เป็นไปได้ที่จะใช้ wrapper ที่รันการทดสอบที่เลือกหรือการทดสอบทั้งหมด

ตัวอย่างเช่น

./run_tests antigravity/*.py

หรือเรียกใช้การทดสอบทั้งหมดซ้ำใช้globbing ( tests/**/*.py) (เปิดใช้งานโดยshopt -s globstar)

เสื้อคลุมสามารถใช้argparseในการแยกอาร์กิวเมนต์โดยทั่วไปเช่น:

parser = argparse.ArgumentParser()
parser.add_argument('files', nargs='*')

จากนั้นโหลดการทดสอบทั้งหมด:

for filename in args.files:
    exec(open(filename).read())

จากนั้นเพิ่มลงในชุดทดสอบของคุณ (โดยใช้inspect):

alltests = unittest.TestSuite()
for name, obj in inspect.getmembers(sys.modules[__name__]):
    if inspect.isclass(obj) and name.startswith("FooTest"):
        alltests.addTest(unittest.makeSuite(obj))

และเรียกใช้พวกเขา:

result = unittest.TextTestRunner(verbosity=2).run(alltests)

ตรวจสอบตัวอย่างนี้สำหรับรายละเอียดเพิ่มเติม

ดูเพิ่มเติม: วิธีรันการทดสอบหน่วย Python ทั้งหมดในไดเรกทอรีได้อย่างไร


4

Python 3+

กำลังเพิ่มลงใน @Pierre

ใช้unittestโครงสร้างไดเรกทอรีเช่นนี้

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

ในการรันโมดูลทดสอบtest_antigravity.py:

$ cd new_project
$ python -m unittest test.test_antigravity

หรือเป็นโสด TestCase

$ python -m unittest test.test_antigravity.GravityTestCase

บังคับไม่ลืม__init__.pyแม้ว่าจะว่างเปล่ามิฉะนั้นจะไม่ทำงาน


2

คุณไม่สามารถนำเข้าจากไดเรกทอรีหลักโดยไม่มีวูดู นี่เป็นอีกวิธีที่ใช้งานได้กับ Python 3.6 เป็นอย่างน้อย

ก่อนอื่นให้ทำการทดสอบไฟล์ / context.py ด้วยเนื้อหาดังต่อไปนี้:

import sys
import os
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))

จากนั้นให้นำเข้าต่อไปนี้ในไฟล์ test / test_antigravity.py:

import unittest
try:
    import context
except ModuleNotFoundError:
    import test.context    
import antigravity

โปรดทราบว่าเหตุผลสำหรับข้อลองนี้ยกเว้นคือ

  • import test.contextล้มเหลวเมื่อเรียกใช้ด้วย "python test_antigravity.py" และ
  • บริบทการนำเข้าล้มเหลวเมื่อเรียกใช้ด้วย "python -m unittest" จากไดเรกทอรี new_project

ด้วยเล่ห์เหลี่ยมนี้พวกเขาทั้งสองทำงาน

ตอนนี้คุณสามารถทำงานได้ทุกไฟล์ทดสอบในสารบบการทดสอบด้วย:

$ pwd
/projects/new_project
$ python -m unittest

หรือเรียกใช้ไฟล์ทดสอบเดี่ยว ๆ ด้วย:

$ cd test
$ python test_antigravity

ตกลงมันไม่ได้สวยกว่าการมีเนื้อหาของ context.py ใน test_antigravity.py แต่อาจจะเล็กน้อย ข้อเสนอแนะยินดีต้อนรับ


2

หากคุณมีหลายไดเรกทอรีในไดเรกทอรีทดสอบคุณต้องเพิ่มแต่ละ__init__.pyไฟล์ในไดเรกทอรี

/home/johndoe/snakeoil
└── test
    ├── __init__.py        
    └── frontend
        └── __init__.py
        └── test_foo.py
    └── backend
        └── __init__.py
        └── test_bar.py

จากนั้นให้เรียกใช้ทุกการทดสอบในครั้งเดียวให้รัน:

python -m unittest discover -s /home/johndoe/snakeoil/test -t /home/johndoe/snakeoil

ที่มา: python -m unittest -h

  -s START, --start-directory START
                        Directory to start discovery ('.' default)
  -t TOP, --top-level-directory TOP
                        Top level directory of project (defaults to start
                        directory)

1

สคริปต์ BASH นี้จะดำเนินการไดเรกทอรีทดสอบ pitt unittest จากที่ใดก็ได้ในระบบไฟล์ไม่ว่าคุณจะอยู่ในไดเรกทอรีทำงานใด

สิ่งนี้มีประโยชน์เมื่ออยู่ในไดเรกทอรีทำงาน./srcหรือ./exampleและคุณต้องการทดสอบหน่วยด่วน:

#!/bin/bash

this_program="$0"
dirname="`dirname $this_program`"
readlink="`readlink -e $dirname`"

python -m unittest discover -s "$readlink"/test -v

ไม่จำเป็นต้องใช้test/__init__.pyไฟล์ในการแพ็คเก็จ / หน่วยความจำ - โอเวอร์เฮดของคุณระหว่างการผลิต


1

วิธีนี้จะช่วยให้คุณเรียกใช้สคริปต์ทดสอบได้จากทุกที่ที่คุณต้องการโดยไม่ต้องยุ่งกับตัวแปรระบบจากบรรทัดคำสั่ง

สิ่งนี้จะเพิ่มโฟลเดอร์โครงการหลักไปยังเส้นทางของหลามพร้อมกับตำแหน่งที่พบที่สัมพันธ์กับสคริปต์นั้นไม่สัมพันธ์กับไดเรกทอรีการทำงานปัจจุบัน

import sys, os

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

เพิ่มที่ด้านบนสุดของสคริปต์ทดสอบทั้งหมดของคุณ ที่จะเพิ่มโฟลเดอร์โครงการหลักไปยังเส้นทางของระบบดังนั้นโมดูลใด ๆ ที่นำเข้าที่ทำงานจากที่นั่นจะทำงาน และไม่สำคัญว่าคุณจะทำการทดสอบจากที่ไหน

คุณสามารถเปลี่ยนไฟล์ project_path_hack เพื่อให้ตรงกับตำแหน่งโฟลเดอร์โครงการหลักของคุณ


0

หากคุณกำลังมองหาวิธีแก้ปัญหาเฉพาะบรรทัดคำสั่ง:

ขึ้นอยู่กับโครงสร้างไดเรกทอรีดังต่อไปนี้ (ทั่วไปกับไดเรกทอรีแหล่งเฉพาะ):

new_project/
    src/
        antigravity.py
    test/
        test_antigravity.py

Windows : (ในnew_project)

$ set PYTHONPATH=%PYTHONPATH%;%cd%\src
$ python -m unittest discover -s test

ดูคำถามนี้หากคุณต้องการใช้สิ่งนี้ในแบตช์ for-loop

Linux : (ในnew_project)

$ export PYTHONPATH=$PYTHONPATH:$(pwd)/src  [I think - please edit this answer if you are a Linux user and you know this]
$ python -m unittest discover -s test

ด้วยวิธีนี้มันเป็นไปได้ที่จะเพิ่มไดเรกทอรีไปยัง PYTHONPATH หากจำเป็น


0

คุณควรใช้เครื่องมือ pip

ใช้pip install -e .เพื่อติดตั้งแพ็คเกจของคุณในโหมดการพัฒนา นี่เป็นแนวปฏิบัติที่ดีมากที่แนะนำโดย pytest (ดูเอกสารแนวทางปฏิบัติที่ดีของพวกเขาซึ่งคุณสามารถหาเค้าโครงโครงการสองโครงการที่จะติดตาม)


ทำไม downvote คำตอบนี้ ฉันอ่านคำตอบที่ได้รับการยอมรับและในขณะที่มันไม่เลวpytestก็เป็นวิธีที่ดีกว่าในการรันการทดสอบเนื่องจากสีของเอาต์พุตคอนโซลที่คุณได้รับในสีพร้อมกับข้อมูลการติดตามสแต็กและข้อมูลข้อผิดพลาดการยืนยันโดยละเอียด
aliopi
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.