ฉันจะรันการทดสอบหน่วย Python ทั้งหมดในไดเรกทอรีได้อย่างไร


315

ฉันมีไดเรกทอรีที่มีการทดสอบหน่วย Python ของฉัน โมดูลหน่วยทดสอบแต่ละที่ของรูปแบบการทดสอบ _ *. PY ฉันกำลังพยายามสร้างไฟล์ที่เรียกว่าall_test.pyซึ่งจะช่วยให้คุณเดาได้ว่ารันไฟล์ทั้งหมดในแบบทดสอบข้างต้นแล้วส่งคืนผลลัพธ์ ฉันได้ลองสองวิธีจนถึงตอนนี้ ทั้งสองล้มเหลว ฉันจะแสดงสองวิธีและฉันหวังว่าจะมีคนรู้วิธีการทำอย่างถูกต้อง

สำหรับความพยายามที่กล้าหาญครั้งแรกของฉันฉันคิดว่า "ถ้าฉันเพียงนำเข้าโมดูลการทดสอบทั้งหมดของฉันในไฟล์แล้วเรียกunittest.main()doodad นี้มันจะทำงานใช่มั้ย" เอาล่ะฉันคิดผิด

import glob
import unittest

testSuite = unittest.TestSuite()
test_file_strings = glob.glob('test_*.py')
module_strings = [str[0:len(str)-3] for str in test_file_strings]

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

สิ่งนี้ไม่ทำงานผลลัพธ์ที่ฉันได้คือ:

$ python all_test.py 

----------------------------------------------------------------------
Ran 0 tests in 0.000s

OK

สำหรับการลองครั้งที่สองของฉันฉันก็โอเคบางทีฉันอาจจะลองทำแบบทดสอบทั้งหมดนี้ในแบบ "แมนนวล" เพิ่มเติม ดังนั้นฉันจึงพยายามที่จะทำด้านล่าง:

import glob
import unittest

testSuite = unittest.TestSuite()
test_file_strings = glob.glob('test_*.py')
module_strings = [str[0:len(str)-3] for str in test_file_strings]
[__import__(str) for str in module_strings]
suites = [unittest.TestLoader().loadTestsFromName(str) for str in module_strings]
[testSuite.addTest(suite) for suite in suites]
print testSuite 

result = unittest.TestResult()
testSuite.run(result)
print result

#Ok, at this point I have a result
#How do I display it as the normal unit test command line output?
if __name__ == "__main__":
    unittest.main()

สิ่งนี้ยังใช้งานไม่ได้ แต่ดูเหมือนใกล้มาก!

$ python all_test.py 
<unittest.TestSuite tests=[<unittest.TestSuite tests=[<unittest.TestSuite tests=[<test_main.TestMain testMethod=test_respondes_to_get>]>]>]>
<unittest.TestResult run=1 errors=0 failures=0>

----------------------------------------------------------------------
Ran 0 tests in 0.000s

OK

ฉันดูเหมือนจะมีชุดของบางอย่างและฉันสามารถเรียกใช้ผลลัพธ์ ฉันกังวลเล็กน้อยเกี่ยวกับความจริงที่ว่าฉันมี แต่run=1ดูเหมือนว่าควรจะเป็นrun=2แต่มันเป็นความคืบหน้า แต่ฉันจะผ่านและแสดงผลลัพธ์ไปยังหลักได้อย่างไร หรือฉันจะทำให้มันใช้งานได้โดยทั่วไปดังนั้นฉันจึงสามารถเรียกใช้ไฟล์นี้และในการทำเช่นนั้นเรียกใช้การทดสอบหน่วยทั้งหมดในไดเรกทอรีนี้?


1
ข้ามไปที่คำตอบของเทรวิสหากคุณใช้ Python 2.7+
Rocky

คุณเคยลองใช้การทดสอบจากวัตถุตัวอย่างการทดสอบหรือไม่
Pinocchio

ดูคำตอบนี้สำหรับโซลูชันที่มีโครงสร้างไฟล์ตัวอย่าง
Derek Soike

คำตอบ:


477

ด้วย Python 2.7 และสูงกว่าคุณไม่จำเป็นต้องเขียนโค้ดใหม่หรือใช้เครื่องมือของบุคคลที่สามในการทำสิ่งนี้ การทดสอบซ้ำโดยใช้บรรทัดคำสั่งนั้นมีอยู่แล้ว ใส่__init__.pyในไดเรกทอรีทดสอบของคุณและ:

python -m unittest discover <test_directory>
# or
python -m unittest discover -s <directory> -p '*_test.py'

คุณสามารถอ่านเพิ่มเติมได้ในเอกสารประกอบสำหรับ unittest python 2.7 หรือpython 3.x


11
ปัญหารวมถึง: ImportError: ไดเรกทอรีเริ่มต้นไม่สามารถนำเข้า:
zinking

6
อย่างน้อยด้วย Python 2.7.8 บน Linux การเรียกใช้บรรทัดคำสั่งไม่ทำให้ฉันเรียกซ้ำได้ โครงการของฉันมีโครงการย่อยหลายโครงการที่มีการทดสอบหน่วยอยู่ในไดเรกทอรี "unit_tests / <subproject> / python /" ที่เกี่ยวข้อง หากฉันระบุพา ธ ดังกล่าวการทดสอบหน่วยสำหรับโครงการย่อยนั้นจะถูกเรียกใช้ แต่มีเพียง "unit_tests" เนื่องจากอาร์กิวเมนต์ของไดเรกทอรีทดสอบไม่พบการทดสอบ (แทนการทดสอบทั้งหมดสำหรับโครงการย่อยทั้งหมดตามที่ฉันหวังไว้) คำใบ้ใด ๆ
user686249

6
เกี่ยวกับการเรียกซ้ำ: คำสั่งแรกที่ไม่มี <test_directory> ค่าเริ่มต้นเป็น "." และเกิดขึ้นซ้ำเพื่อsubmodules นั่นคือไดเรกทอรีทดสอบทั้งหมดที่คุณต้องการค้นพบจำเป็นต้องมีinit .py หากพวกเขาทำเช่นนั้นพวกเขาจะพบโดยคำสั่ง Discover เพิ่งลองมันใช้งานได้
Emil Stenström

สิ่งนี้ใช้ได้สำหรับฉัน ฉันมีโฟลเดอร์ทดสอบที่มีสี่ไฟล์เรียกใช้จากเทอร์มินัล Linux ของฉันสิ่งที่ยอดเยี่ยม
JasTonAChair

5
ขอบคุณ! ทำไมนี่ไม่ใช่คำตอบที่ยอมรับ? ในมุมมองของฉันคำตอบที่ดีกว่าคือคำตอบที่ไม่ต้องการการพึ่งพาจากภายนอกเสมอไป ...
Jonathan Benn

108

คุณสามารถใช้นักวิ่งทดสอบที่จะทำสิ่งนี้เพื่อคุณ ยกตัวอย่างเช่นจมูกดีมาก เมื่อรันจะพบการทดสอบในแผนผังปัจจุบันและเรียกใช้

Updated:

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

testmodules = [
    'cogapp.test_makefiles',
    'cogapp.test_whiteutils',
    'cogapp.test_cogapp',
    ]

suite = unittest.TestSuite()

for t in testmodules:
    try:
        # If the module defines a suite() function, call it to get the suite.
        mod = __import__(t, globals(), locals(), ['suite'])
        suitefn = getattr(mod, 'suite')
        suite.addTest(suitefn())
    except (ImportError, AttributeError):
        # else, just load all the test cases from the module.
        suite.addTest(unittest.defaultTestLoader.loadTestsFromName(t))

unittest.TextTestRunner().run(suite)

2
ข้อดีของวิธีนี้คือการนำเข้าโมดูลทดสอบทั้งหมดของคุณไปยังโมดูล test_all.py และเรียกใช้ unittest.main () อย่างชัดเจนซึ่งคุณสามารถเลือกที่จะประกาศชุดทดสอบในบางโมดูลได้
Corey Porter

1
ฉันลองจมูกแล้วก็ใช้งานได้อย่างสมบูรณ์ มันง่ายในการติดตั้งและรันในโครงการของฉัน ฉันยังสามารถทำให้เป็นอัตโนมัติด้วยสคริปต์สองสามบรรทัดทำงานใน virtualenv +1 สำหรับจมูก!
Jesse Webb

ไม่สามารถทำได้เสมอ: บางครั้งการนำเข้าโครงสร้างของโครงการอาจทำให้จมูกสับสนได้หากพยายามเรียกใช้การนำเข้าบนโมดูล
chiffa

4
โปรดทราบว่าจมูกได้รับ "อยู่ในโหมดการบำรุงรักษาในช่วงหลายปีที่ผ่านมา" และในปัจจุบันได้แนะนำให้ใช้nose2 , pytestหรือเพียงแค่unittest / unittest2สำหรับโครงการใหม่
Kurt Peek

คุณเคยลองใช้การทดสอบจากวัตถุตัวอย่างการทดสอบหรือไม่
Pinocchio

96

ใน python 3 ถ้าคุณใช้unittest.TestCase:

  • คุณต้องมีไฟล์ว่างเปล่า (หรือมิฉะนั้น) __init__.pyในtestไดเรกทอรีของคุณ( ต้องมีชื่อtest/ )
  • ไฟล์ทดสอบของคุณภายในตรงกับรูปแบบtest/ test_*.pyพวกเขาสามารถอยู่ในไดเรกทอรีย่อยภายใต้test/และย่อยเหล่านั้นสามารถตั้งชื่อเป็นอะไรก็ได้

จากนั้นคุณสามารถทำการทดสอบทั้งหมดด้วย:

python -m unittest

ทำ! วิธีแก้ปัญหาน้อยกว่า 100 บรรทัด หวังว่าผู้เริ่มต้น python อีกรายจะช่วยประหยัดเวลาโดยการค้นหาสิ่งนี้


3
โปรดทราบว่าโดยค่าเริ่มต้นจะค้นหาเฉพาะการทดสอบในชื่อไฟล์ที่ขึ้นต้นด้วย "test"
Shawabawa

3
ถูกต้องคำถามเดิมที่อ้างถึงความจริงที่ว่า "โมดูลทดสอบแต่ละหน่วยเป็นรูปแบบการทดสอบ _ *. py." ดังนั้นคำตอบนี้เป็นการตอบกลับโดยตรง ตอนนี้ฉันได้ปรับปรุงคำตอบให้ชัดเจนยิ่งขึ้นแล้ว
tmck-code

1
ขอบคุณสิ่งที่ขาดหายไปสำหรับฉันคือใช้คำตอบของ Travis Bear
Jeremy Cochoy

65

นี่คือตอนนี้ไปได้โดยตรงจาก UnitTest: unittest.TestLoader.discover

import unittest
loader = unittest.TestLoader()
start_dir = 'path/to/your/test/files'
suite = loader.discover(start_dir)

runner = unittest.TextTestRunner()
runner.run(suite)

3
ฉันได้ลองวิธีนี้แล้วยังมีการทดสอบสองสามอย่าง แต่ทำงานได้อย่างสมบูรณ์ ที่ดีเยี่ยม !!! แต่ฉันอยากรู้ว่าฉันมีเพียง 4 การทดสอบ พวกเขาช่วยกันรัน 0.032 วินาที แต่เมื่อฉันใช้วิธีนี้เพื่อเรียกใช้พวกเขาทั้งหมดฉันจะได้ผลลัพธ์.... ---------------------------------------------------------------------- Ran 4 tests in 0.000s OKทำไม? ความแตกต่างมันมาจากไหน?
simkus

ฉันมีปัญหาในการเรียกใช้ไฟล์ที่มีลักษณะเช่นนี้จากบรรทัดคำสั่ง ควรจะเรียกใช้อย่างไร
ดัสตินมิเชล

python file.py
ฆ่า

1
ทำงานไร้ที่ติ! เพียงแค่ตั้งค่าในการทดสอบ / dir ของคุณแล้วตั้ง start_id = "./" IMHO คำตอบนี้คือ (Python 3.7) วิธีที่ยอมรับ!
jjwdesign

คุณสามารถเปลี่ยนบรรทัดสุดท้ายเป็น´res = runner.run (ชุด); sys.exit (0 ถ้า res.wasSuccessful () อื่น 1) ´ถ้าคุณต้องการรหัสออกที่ถูกต้อง
Sadap

32

ด้วยการศึกษาโค้ดข้างต้นเล็กน้อย (โดยเฉพาะการใช้TextTestRunnerและdefaultTestLoader) ฉันสามารถเข้าใกล้ได้ ในที่สุดฉันก็แก้ไขโค้ดของฉันโดยเพียงแค่ส่งชุดทดสอบทั้งหมดไปยังคอนสตรัคเตอร์ชุดเดียวแทนที่จะเพิ่ม "ด้วยตนเอง" ซึ่งแก้ไขปัญหาอื่น ๆ ของฉัน นี่คือทางออกของฉัน

import glob
import unittest

test_files = glob.glob('test_*.py')
module_strings = [test_file[0:len(test_file)-3] for test_file in test_files]
suites = [unittest.defaultTestLoader.loadTestsFromName(test_file) for test_file in module_strings]
test_suite = unittest.TestSuite(suites)
test_runner = unittest.TextTestRunner().run(test_suite)

ใช่มันอาจจะง่ายกว่าที่จะใช้แค่จมูกมากกว่าทำแบบนี้ แต่มันอยู่นอกเหนือประเด็น


ดีมันทำงานได้ดีสำหรับไดเรกทอรีปัจจุบันวิธีการเรียกย่อยโดยตรง?
Larry Cai

ลาร์รี่ดูคำตอบใหม่ ( stackoverflow.com/a/24562019/104143 ) สำหรับการค้นพบการทดสอบซ้ำ
Peter Kofler

คุณเคยลองใช้การทดสอบจากวัตถุตัวอย่างการทดสอบหรือไม่
Pinocchio

25

หากคุณต้องการเรียกใช้การทดสอบทั้งหมดจากคลาสกรณีทดสอบที่หลากหลายและคุณยินดีที่จะระบุอย่างชัดเจนคุณสามารถทำได้ดังนี้:

from unittest import TestLoader, TextTestRunner, TestSuite
from uclid.test.test_symbols import TestSymbols
from uclid.test.test_patterns import TestPatterns

if __name__ == "__main__":

    loader = TestLoader()
    tests = [
        loader.loadTestsFromTestCase(test)
        for test in (TestSymbols, TestPatterns)
    ]
    suite = TestSuite(tests)

    runner = TextTestRunner(verbosity=2)
    runner.run(suite)

uclidโครงการของฉันอยู่ที่ไหนTestSymbolsและTestPatternsอยู่ที่TestCaseใด


จากunittest.TestLoader docs : "โดยปกติไม่จำเป็นต้องสร้างอินสแตนซ์ของคลาสนี้โมดูล unittest จัดเตรียมอินสแตนซ์ที่สามารถแชร์เป็น unittest.defaultTestLoader ได้" นอกจากนี้ตั้งแต่TestSuiteยอมรับiterableเป็นอาร์กิวเมนต์คุณสามารถสร้างกล่าวว่า iterable loader.loadTestsFromTestCaseในวงที่จะหลีกเลี่ยงการทำซ้ำ
นักเล่นแร่แปรธาตุ Two-Bit

@ Two-Bit Alchemist จุดที่สองของคุณโดยเฉพาะดีมาก ฉันจะเปลี่ยนรหัสเพื่อรวม แต่ไม่สามารถทดสอบได้ (ตัวดัดแปลงแรกจะทำให้มันดูเหมือน Java มากเกินไปสำหรับความชอบของฉัน .. แม้ว่าฉันจะรู้ว่าฉันไม่มีเหตุผล (ไขพวกเขาเป็นชื่อตัวแปรกรณีอูฐ)
Hedgehog สมองเสื่อม

นี่คือรายการโปรดของฉันสะอาดมาก สามารถจัดแพคเกจนี้และทำให้มันเป็นอาร์กิวเมนต์ในบรรทัดคำสั่งปกติของฉัน
MarkII

15

ฉันใช้discoverวิธีการและการโอเวอร์โหลดload_testsเพื่อให้ได้ผลลัพธ์นี้ในบรรทัดของโค้ดจำนวน (น้อยที่สุดฉันคิดว่า):

def load_tests(loader, tests, pattern):
''' Discover and load all unit tests in all files named ``*_test.py`` in ``./src/``
'''
    suite = TestSuite()
    for all_test_suite in unittest.defaultTestLoader.discover('src', pattern='*_tests.py'):
        for test_suite in all_test_suite:
            suite.addTests(test_suite)
    return suite

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

การประหารชีวิตจะทำอะไรที่คล้ายกัน

Ran 27 tests in 0.187s
OK

นี้ใช้ได้สำหรับ python2.7 เท่านั้นฉันเดา
Larry Cai

@larrycai บางทีฉันมักจะอยู่ใน Python 3 บางครั้ง Python 2.7 คำถามไม่ได้เชื่อมโยงกับรุ่นที่เฉพาะเจาะจง
rds

ฉันใช้ Python 3.4 และค้นพบการคืนค่าชุดทำให้วนซ้ำซ้อน
Dunes

สำหรับอนาคตของ Larry: "มีการเพิ่มฟีเจอร์ใหม่ ๆ ให้กับ unittest ใน Python 2.7 รวมถึงการค้นพบการทดสอบunittest2ช่วยให้คุณสามารถใช้คุณสมบัติเหล่านี้กับ Python เวอร์ชันก่อนหน้าได้"
นักเล่นแร่แปรธาตุ Two-Bit

8

ฉันลองวิธีการต่าง ๆ แต่ดูเหมือนว่ามีข้อบกพร่องหรือฉันต้องแต่งหน้าโค้ดบางอย่างมันน่ารำคาญ แต่มีวิธีที่ชัดเจนภายใต้ลินุกซ์นั่นคือการค้นหาทุกการทดสอบผ่านรูปแบบที่แน่นอนแล้วเรียกใช้พวกเขาทีละคน

find . -name 'Test*py' -exec python '{}' \;

และที่สำคัญที่สุดใช้งานได้แน่นอน


7

ในกรณีของไลบรารีหรือแอปพลิเคชันที่บรรจุแล้วคุณไม่ต้องการทำเช่นนั้น จะทำเพื่อคุณsetuptools

ในการใช้คำสั่งนี้การทดสอบโปรเจ็กต์ของคุณจะต้องห่อในunittestชุดทดสอบโดยฟังก์ชันคลาสหรือเมธอด TestCase หรือโมดูลหรือแพ็กเกจที่มีTestCaseคลาส หากชุดที่มีชื่อเป็นโมดูลและโมดูลมีadditional_tests()ฟังก์ชั่นจะมีการเรียกใช้และเพิ่มผลลัพธ์ (ซึ่งต้องเป็น a unittest.TestSuite) ลงในการทดสอบที่จะเรียกใช้ ถ้าชุดที่มีชื่อเป็นแพคเกจที่submodules ใด ๆ และจะมีการเพิ่มแพ็กเกจย่อยซ้ำกับชุดทดสอบโดยรวม

เพียงแค่บอกว่าแพ็คเกจการทดสอบรูตของคุณอยู่ที่ใดเช่น:

setup(
    # ...
    test_suite = 'somepkg.test'
)

และวิ่งได้ python setup.py testได้

การค้นพบโดยใช้ไฟล์อาจเป็นปัญหาใน Python 3 เว้นแต่ว่าคุณจะหลีกเลี่ยงการนำเข้าที่เกี่ยวข้องในชุดทดสอบของคุณเพราะdiscoverใช้การนำเข้าไฟล์ แม้ว่าจะสนับสนุนทางเลือกtop_level_dirแต่ฉันมีข้อผิดพลาดการเรียกซ้ำไม่สิ้นสุด ดังนั้นวิธีแก้ปัญหาอย่างง่ายสำหรับโค้ดที่ไม่ทำแพ็กเกจคือการใส่สิ่งต่อไปนี้ใน__init__.pyแพ็คเกจทดสอบของคุณ (ดูที่load_tests Protocol )

import unittest

from . import foo, bar


def load_tests(loader, tests, pattern):
    suite = unittest.TestSuite()
    suite.addTests(loader.loadTestsFromModule(foo))
    suite.addTests(loader.loadTestsFromModule(bar))

    return suite

คำตอบที่ดีและมันสามารถใช้ในการทดสอบอัตโนมัติก่อนที่จะปรับใช้! ขอบคุณ
Arthur Clerc-Gherardi

4

ฉันใช้ PyDev / LiClipse และไม่ได้คิดวิธีการทดสอบทั้งหมดในคราวเดียวจาก GUI (แก้ไข: คุณคลิกขวาที่โฟลเดอร์ทดสอบรากและเลือกRun as -> Python unit-test

นี่เป็นวิธีแก้ปัญหาปัจจุบันของฉัน:

import unittest

def load_tests(loader, tests, pattern):
    return loader.discover('.')

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

ฉันใส่รหัสนี้ในโมดูลที่เรียกว่าallในไดเรกทอรีทดสอบของฉัน ถ้าฉันเรียกใช้โมดูลนี้เป็นแบบ unittest จาก LiClipse การทดสอบทั้งหมดจะถูกเรียกใช้ ถ้าฉันขอให้ทำซ้ำการทดสอบที่เฉพาะเจาะจงหรือล้มเหลวเท่านั้นการทดสอบเหล่านั้นจะทำงาน มันไม่ได้รบกวนนักวิ่งทดสอบ commandline ของฉัน (nosetests) - มันถูกละเว้น

คุณอาจต้องเปลี่ยนข้อโต้แย้งเป็นไปdiscoverตามการตั้งค่าโครงการของคุณ


ชื่อของไฟล์ทดสอบและวิธีทดสอบควรเริ่มต้นด้วย "test_" มิฉะนั้นคำสั่ง "Run as -> Python unit test" จะไม่พบมัน
Stefan

2

จากคำตอบของStephen Cagleฉันเพิ่มการสนับสนุนสำหรับโมดูลการทดสอบที่ซ้อนกัน

import fnmatch
import os
import unittest

def all_test_modules(root_dir, pattern):
    test_file_names = all_files_in(root_dir, pattern)
    return [path_to_module(str) for str in test_file_names]

def all_files_in(root_dir, pattern):
    matches = []

    for root, dirnames, filenames in os.walk(root_dir):
        for filename in fnmatch.filter(filenames, pattern):
            matches.append(os.path.join(root, filename))

    return matches

def path_to_module(py_file):
    return strip_leading_dots( \
        replace_slash_by_dot(  \
            strip_extension(py_file)))

def strip_extension(py_file):
    return py_file[0:len(py_file) - len('.py')]

def replace_slash_by_dot(str):
    return str.replace('\\', '.').replace('/', '.')

def strip_leading_dots(str):
    while str.startswith('.'):
       str = str[1:len(str)]
    return str

module_names = all_test_modules('.', '*Tests.py')
suites = [unittest.defaultTestLoader.loadTestsFromName(mname) for mname 
    in module_names]

testSuite = unittest.TestSuite(suites)
runner = unittest.TextTestRunner(verbosity=1)
runner.run(testSuite)

รหัสการค้นหาไดเรกทอรีย่อยทั้งหมดของ.สำหรับ*Tests.pyไฟล์ที่ถูกโหลดแล้ว มันคาดว่าแต่ละคน*Tests.pyจะมีชั้นเดียว*Tests(unittest.TestCase)ซึ่งถูกโหลดในทางกลับกันและดำเนินการหนึ่งหลังจากที่อื่น

สิ่งนี้ใช้ได้กับการทำรังไดเรกทอรี / โมดูลโดยพลการ แต่อย่างใด แต่ในแต่ละไดเรกทอรีนั้นจำเป็นต้องมี__init__.pyไฟล์ว่างอย่างน้อย วิธีนี้ช่วยให้การทดสอบโหลดโมดูลที่ซ้อนกันโดยการแทนที่เครื่องหมายสแลช (หรือแบ็กสแลช) โดยจุด (ดูreplace_slash_by_dot)


2

นี่เป็นคำถามเก่า แต่สิ่งที่ได้ผลสำหรับฉันตอนนี้ (ในปี 2019) คือ:

python -m unittest *_test.py

_testไฟล์ทั้งหมดในการทดสอบของฉันอยู่ในโฟลเดอร์เดียวกับไฟล์ที่มาและพวกเขาจบลงด้วย



1

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

การทดสอบทั้งหมดเป็นอิสระ $ PWD

โมดูลหลาม unittest มีความไวต่อไดเรกทอรีปัจจุบันของคุณเว้นแต่คุณจะบอกได้ที่ไหน (ใช้discover -sตัวเลือก)

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

#!/bin/bash
this_program="$0"
dirname="`dirname $this_program`"
readlink="`readlink -e $dirname`"

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

การทดสอบที่เลือกอิสระ $ PWD

ฉันชื่อไฟล์ยูทิลิตี้นี้runone.pyและใช้มันเช่นนี้:

runone.py <test-python-filename-minus-dot-py-fileextension>
#!/bin/bash
this_program="$0"
dirname="`dirname $this_program`"
readlink="`readlink -e $dirname`"

(cd "$dirname"/test; python -m unittest $1)

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


-3

นี่คือวิธีของฉันโดยการสร้างwrapperเพื่อทำการทดสอบจากบรรทัดคำสั่ง:

#!/usr/bin/env python3
import os, sys, unittest, argparse, inspect, logging

if __name__ == '__main__':
    # Parse arguments.
    parser = argparse.ArgumentParser(add_help=False)
    parser.add_argument("-?", "--help",     action="help",                        help="show this help message and exit" )
    parser.add_argument("-v", "--verbose",  action="store_true", dest="verbose",  help="increase output verbosity" )
    parser.add_argument("-d", "--debug",    action="store_true", dest="debug",    help="show debug messages" )
    parser.add_argument("-h", "--host",     action="store",      dest="host",     help="Destination host" )
    parser.add_argument("-b", "--browser",  action="store",      dest="browser",  help="Browser driver.", choices=["Firefox", "Chrome", "IE", "Opera", "PhantomJS"] )
    parser.add_argument("-r", "--reports-dir", action="store",   dest="dir",      help="Directory to save screenshots.", default="reports")
    parser.add_argument('files', nargs='*')
    args = parser.parse_args()

    # Load files from the arguments.
    for filename in args.files:
        exec(open(filename).read())

    # See: http://codereview.stackexchange.com/q/88655/15346
    def make_suite(tc_class):
        testloader = unittest.TestLoader()
        testnames = testloader.getTestCaseNames(tc_class)
        suite = unittest.TestSuite()
        for name in testnames:
            suite.addTest(tc_class(name, cargs=args))
        return suite

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

    # Set-up logger
    verbose = bool(os.environ.get('VERBOSE', args.verbose))
    debug   = bool(os.environ.get('DEBUG', args.debug))
    if verbose or debug:
        logging.basicConfig( stream=sys.stdout )
        root = logging.getLogger()
        root.setLevel(logging.INFO if verbose else logging.DEBUG)
        ch = logging.StreamHandler(sys.stdout)
        ch.setLevel(logging.INFO if verbose else logging.DEBUG)
        ch.setFormatter(logging.Formatter('%(asctime)s %(levelname)s: %(name)s: %(message)s'))
        root.addHandler(ch)
    else:
        logging.basicConfig(stream=sys.stderr)

    # Run tests.
    result = unittest.TextTestRunner(verbosity=2).run(alltests)
    sys.exit(not result.wasSuccessful())

เพื่อความเรียบง่ายโปรดขอโทษมาตรฐานการเข้ารหัสที่ไม่ใช่PEP8ของฉัน

จากนั้นคุณสามารถสร้างคลาส BaseTest สำหรับส่วนประกอบทั่วไปสำหรับการทดสอบทั้งหมดของคุณดังนั้นการทดสอบแต่ละครั้งจะมีลักษณะดังนี้:

from BaseTest import BaseTest
class FooTestPagesBasic(BaseTest):
    def test_foo(self):
        driver = self.driver
        driver.get(self.base_url + "/")

ในการรันคุณเพียงแค่ระบุการทดสอบเป็นส่วนหนึ่งของอาร์กิวเมนต์บรรทัดคำสั่งเช่น:

./run_tests.py -h http://example.com/ tests/**/*.py

2
คำตอบส่วนใหญ่ไม่มีส่วนเกี่ยวข้องกับการค้นพบทดสอบ (เช่นการบันทึกเป็นต้น) Stack Overflow ใช้สำหรับตอบคำถามไม่แสดงรหัสที่ไม่เกี่ยวข้อง
Corey Goldberg
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.