PyUnit/UnittestDialog.py

changeset 6899
8c4cf9c405c7
parent 6897
701256697721
child 6900
060a30488316
equal deleted inserted replaced
6898:6d7e8a05a33c 6899:8c4cf9c405c7
16 import os 16 import os
17 17
18 from PyQt5.QtCore import pyqtSignal, QEvent, Qt, pyqtSlot 18 from PyQt5.QtCore import pyqtSignal, QEvent, Qt, pyqtSlot
19 from PyQt5.QtGui import QColor 19 from PyQt5.QtGui import QColor
20 from PyQt5.QtWidgets import QWidget, QDialog, QApplication, QDialogButtonBox, \ 20 from PyQt5.QtWidgets import QWidget, QDialog, QApplication, QDialogButtonBox, \
21 QListWidgetItem, QComboBox 21 QListWidgetItem, QComboBox, QTreeWidgetItem
22 22
23 from E5Gui.E5Application import e5App 23 from E5Gui.E5Application import e5App
24 from E5Gui import E5MessageBox 24 from E5Gui import E5MessageBox
25 from E5Gui.E5MainWindow import E5MainWindow 25 from E5Gui.E5MainWindow import E5MainWindow
26 from E5Gui.E5PathPicker import E5PathPickerModes 26 from E5Gui.E5PathPicker import E5PathPickerModes
74 self.discoveryPicker.setInsertPolicy(QComboBox.InsertAtTop) 74 self.discoveryPicker.setInsertPolicy(QComboBox.InsertAtTop)
75 self.discoveryPicker.setSizeAdjustPolicy( 75 self.discoveryPicker.setSizeAdjustPolicy(
76 QComboBox.AdjustToMinimumContentsLength) 76 QComboBox.AdjustToMinimumContentsLength)
77 77
78 # TODO: add a "Discover" button enabled upon selection of 'auto-discovery' 78 # TODO: add a "Discover" button enabled upon selection of 'auto-discovery'
79 self.discoverButton = self.buttonBox.addButton(
80 self.tr("Discover"), QDialogButtonBox.ActionRole)
81 self.discoverButton.setToolTip(self.tr(
82 "Discover tests"))
83 self.discoverButton.setWhatsThis(self.tr(
84 """<b>Discover</b>"""
85 """<p>This button starts a discovery of available tests.</p>"""))
79 self.startButton = self.buttonBox.addButton( 86 self.startButton = self.buttonBox.addButton(
80 self.tr("Start"), QDialogButtonBox.ActionRole) 87 self.tr("Start"), QDialogButtonBox.ActionRole)
81 self.startButton.setToolTip(self.tr( 88 self.startButton.setToolTip(self.tr(
82 "Start the selected testsuite")) 89 "Start the selected testsuite"))
83 self.startButton.setWhatsThis(self.tr( 90 self.startButton.setWhatsThis(self.tr(
95 self.tr("Stop"), QDialogButtonBox.ActionRole) 102 self.tr("Stop"), QDialogButtonBox.ActionRole)
96 self.stopButton.setToolTip(self.tr("Stop the running unittest")) 103 self.stopButton.setToolTip(self.tr("Stop the running unittest"))
97 self.stopButton.setWhatsThis(self.tr( 104 self.stopButton.setWhatsThis(self.tr(
98 """<b>Stop Test</b>""" 105 """<b>Stop Test</b>"""
99 """<p>This button stops a running unittest.</p>""")) 106 """<p>This button stops a running unittest.</p>"""))
107 self.discoverButton.setEnabled(False)
100 self.stopButton.setEnabled(False) 108 self.stopButton.setEnabled(False)
101 self.startButton.setDefault(True) 109 self.startButton.setDefault(True)
102 self.startFailedButton.setEnabled(False) 110 self.startFailedButton.setEnabled(False)
103 111
104 self.__dbs = dbs 112 self.__dbs = dbs
316 Private slot handling state changes of the 'discover' checkbox. 324 Private slot handling state changes of the 'discover' checkbox.
317 325
318 @param checked state of the checkbox 326 @param checked state of the checkbox
319 @type bool 327 @type bool
320 """ 328 """
321 # TODO: enable this code once the discover button is available 329 self.discoverButton.setEnabled(checked)
322 # self.discoverButton.setEnabled(checked) 330 if not bool(self.discoveryPicker.currentText()):
331 if self.__forProject:
332 project = e5App().getObject("Project")
333 if project.isOpen():
334 self.insertDiscovery(project.getProjectPath())
335 return
336
337 self.insertDiscovery(Preferences.getMultiProject("Workspace"))
323 338
324 def on_buttonBox_clicked(self, button): 339 def on_buttonBox_clicked(self, button):
325 """ 340 """
326 Private slot called by a button of the button box clicked. 341 Private slot called by a button of the button box clicked.
327 342
328 @param button button that was clicked (QAbstractButton) 343 @param button button that was clicked (QAbstractButton)
329 """ 344 """
330 if button == self.startButton: 345 if button == self.discoverButton:
346 self.__discover()
347 elif button == self.startButton:
331 self.startTests() 348 self.startTests()
332 elif button == self.stopButton: 349 elif button == self.stopButton:
333 self.__stopTests() 350 self.__stopTests()
334 elif button == self.startFailedButton: 351 elif button == self.startFailedButton:
335 self.startTests(failedOnly=True) 352 self.startTests(failedOnly=True)
353
354 @pyqtSlot()
355 def __discover(self):
356 """
357 Private slot to discover unit test but don't run them.
358 """
359 if self.running:
360 return
361
362 self.discoveryList.clear()
363
364 discoveryStart = self.discoveryPicker.currentText()
365 self.sbLabel.setText(self.tr("Discovering Tests"))
366 QApplication.processEvents()
367
368 self.testName = self.tr("Unittest with auto-discovery")
369 if self.__dbs:
370 # TODO: implement this later
371 pass
372 else:
373 # we are running as an application
374 if not discoveryStart:
375 E5MessageBox.critical(
376 self,
377 self.tr("Unittest"),
378 self.tr("You must enter a start directory for"
379 " auto-discovery."))
380 return
381
382 # clean up list of imported modules to force a reimport upon
383 # running the test
384 if self.savedModulelist:
385 for modname in list(sys.modules.keys()):
386 if modname not in self.savedModulelist:
387 # delete it
388 del(sys.modules[modname])
389 self.savedModulelist = sys.modules.copy()
390
391 # now try to discover the testsuite
392 os.chdir(discoveryStart)
393 try:
394 test = unittest.defaultTestLoader.discover(discoveryStart)
395 if test:
396 testsList = self.__assembleTestCasesList(test)
397 self.__populateDiscoveryResults(testsList)
398 self.sbLabel.setText(
399 self.tr("Discovered %n Test(s)", "", len(testsList)))
400 self.tabWidget.setCurrentIndex(0)
401 except Exception:
402 exc_type, exc_value, exc_tb = sys.exc_info()
403 E5MessageBox.critical(
404 self,
405 self.tr("Unittest"),
406 self.tr(
407 "<p>Unable to discover tests.<br/>"
408 "{0}<br/>{1}</p>")
409 .format(str(exc_type), str(exc_value)))
410
411 def __assembleTestCasesList(self, suite):
412 """
413 Private method to assemble a list of test cases included in a test
414 suite.
415
416 @param suite test suite to be inspected
417 @type unittest.TestSuite
418 @return list of tuples containing the test case ID and short
419 description
420 @rtype list of tuples of (str, str)
421 """
422 testCases = []
423 for test in suite:
424 if isinstance(test, unittest.TestSuite):
425 testCases.extend(self.__assembleTestCasesList(test))
426 else:
427 testCases.append((test.id(), test.shortDescription()))
428 return testCases
429
430 def __findDiscoveryItem(self, modulePath):
431 """
432 Private method to find an item given the module path.
433
434 @param modulePath path of the module in dotted notation
435 @type str
436 @return reference to the item or None
437 @rtype QTreeWidgetItem or None
438 """
439 itm = self.discoveryList.topLevelItem(0)
440 while itm is not None:
441 if itm.data(0, Qt.UserRole) == modulePath:
442 return itm
443 itm = self.discoveryList.itemBelow(itm)
444
445 return None
446
447 def __populateDiscoveryResults(self, tests):
448 """
449 Private method to populate the test discovery results list.
450
451 @param tests list of tuples containing the discovery results
452 @type list of tuples of (str, str)
453 """
454 for test, _testDescription in tests:
455 testPath = test.split(".")
456 pitm = None
457 for index in range(1, len(testPath) + 1):
458 modulePath = ".".join(testPath[:index])
459 itm = self.__findDiscoveryItem(modulePath)
460 if itm is not None:
461 pitm = itm
462 else:
463 if pitm is None:
464 itm = QTreeWidgetItem(self.discoveryList,
465 [testPath[index - 1]])
466 else:
467 itm = QTreeWidgetItem(pitm,
468 [testPath[index - 1]])
469 pitm.setExpanded(True)
470 itm.setFlags(Qt.ItemIsUserCheckable | Qt.ItemIsEnabled)
471 itm.setCheckState(0, Qt.Unchecked)
472 itm.setData(0, Qt.UserRole, modulePath)
473 pitm = itm
336 474
337 @pyqtSlot() 475 @pyqtSlot()
338 def startTests(self, failedOnly=False): 476 def startTests(self, failedOnly=False):
339 """ 477 """
340 Public slot to start the test. 478 Public slot to start the test.
464 return 602 return
465 603
466 if testFileName: 604 if testFileName:
467 sys.path = [os.path.dirname(os.path.abspath(testFileName))] + \ 605 sys.path = [os.path.dirname(os.path.abspath(testFileName))] + \
468 self.savedSysPath 606 self.savedSysPath
607 elif discoveryStart:
608 sys.path = [os.path.abspath(discoveryStart)] + \
609 self.savedSysPath
469 610
470 # clean up list of imported modules to force a reimport upon 611 # clean up list of imported modules to force a reimport upon
471 # running the test 612 # running the test
472 if self.savedModulelist: 613 if self.savedModulelist:
473 for modname in list(sys.modules.keys()): 614 for modname in list(sys.modules.keys()):
487 discover = False 628 discover = False
488 else: 629 else:
489 failed = [] 630 failed = []
490 if discover: 631 if discover:
491 test = unittest.defaultTestLoader.discover(discoveryStart) 632 test = unittest.defaultTestLoader.discover(discoveryStart)
492 # testsList = self.__assembleTestCasesList(test)
493 else: 633 else:
494 if testFileName: 634 if testFileName:
495 module = __import__(self.testName) 635 module = __import__(self.testName)
496 else: 636 else:
497 module = None 637 module = None
546 cover.stop() 686 cover.stop()
547 cover.save() 687 cover.save()
548 self.__setStoppedMode() 688 self.__setStoppedMode()
549 sys.path = self.savedSysPath 689 sys.path = self.savedSysPath
550 690
551 def __assembleTestCasesList(self, suite):
552 """
553 Private method to assemble a list of test cases included in a test
554 suite.
555
556 @param suite test suite to be inspected
557 @type unittest.TestSuite
558 @return list of tuples containing the test case ID and short
559 description
560 @rtype list of tuples of (str, str)
561 """
562 testCases = []
563 for test in suite:
564 if isinstance(test, unittest.TestSuite):
565 testCases.extend(self.__assembleTestCasesList(test))
566 else:
567 testCases.append((test.id(), test.shortDescription()))
568 return testCases
569
570 def __UTPrepared(self, nrTests, exc_type, exc_value): 691 def __UTPrepared(self, nrTests, exc_type, exc_value):
571 """ 692 """
572 Private slot to handle the utPrepared signal. 693 Private slot to handle the utPrepared signal.
573 694
574 If the unittest suite was loaded successfully, we ask the 695 If the unittest suite was loaded successfully, we ask the

eric ide

mercurial