PyUnit/UnittestDialog.py

changeset 6896
3716c4af48bb
parent 6894
df83ac87e0db
child 6897
701256697721
equal deleted inserted replaced
6895:681a06d12ef6 6896:3716c4af48bb
73 self.discoveryPicker.setMode(E5PathPickerModes.DirectoryMode) 73 self.discoveryPicker.setMode(E5PathPickerModes.DirectoryMode)
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 self.startButton = self.buttonBox.addButton( 79 self.startButton = self.buttonBox.addButton(
79 self.tr("Start"), QDialogButtonBox.ActionRole) 80 self.tr("Start"), QDialogButtonBox.ActionRole)
80 self.startButton.setToolTip(self.tr( 81 self.startButton.setToolTip(self.tr(
81 "Start the selected testsuite")) 82 "Start the selected testsuite"))
82 self.startButton.setWhatsThis(self.tr( 83 self.startButton.setWhatsThis(self.tr(
109 self.setWindowIcon(UI.PixmapCache.getIcon("eric.png")) 110 self.setWindowIcon(UI.PixmapCache.getIcon("eric.png"))
110 self.setWindowTitle(self.tr("Unittest")) 111 self.setWindowTitle(self.tr("Unittest"))
111 if dbs: 112 if dbs:
112 self.ui = ui 113 self.ui = ui
113 114
114 self.venvComboBox.addItem("") 115 # virtual environment manager is only used in the integrated
115 self.venvComboBox.addItems( 116 # variant
116 sorted(e5App().getObject("VirtualEnvManager") 117 self.__venvManager = e5App().getObject("VirtualEnvManager")
117 .getVirtualenvNames())) 118 self.__populateVenvComboBox()
118 self.venvComboBox.setVisible(bool(self.__dbs)) 119 self.__venvManager.virtualEnvironmentAdded.connect(
119 self.venvLabel.setVisible(bool(self.__dbs)) 120 self.__populateVenvComboBox)
121 self.__venvManager.virtualEnvironmentRemoved.connect(
122 self.__populateVenvComboBox)
123 self.__venvManager.virtualEnvironmentChanged.connect(
124 self.__populateVenvComboBox)
125 else:
126 self.__venvManager = None
127 self.venvComboBox.setVisible(bool(self.__venvManager))
128 self.venvLabel.setVisible(bool(self.__venvManager))
120 129
121 self.__setProgressColor("green") 130 self.__setProgressColor("green")
122 self.progressLed.setDarkFactor(150) 131 self.progressLed.setDarkFactor(150)
123 self.progressLed.off() 132 self.progressLed.off()
124 133
162 171
163 @param evt key press event to handle (QKeyEvent) 172 @param evt key press event to handle (QKeyEvent)
164 """ 173 """
165 if evt.key() == Qt.Key_Escape and self.__dbs: 174 if evt.key() == Qt.Key_Escape and self.__dbs:
166 self.close() 175 self.close()
176
177 def __populateVenvComboBox(self):
178 """
179 Private method to (re-)populate the virtual environments selector.
180 """
181 currentText = self.venvComboBox.currentText()
182 self.venvComboBox.clear()
183 self.venvComboBox.addItem("")
184 self.venvComboBox.addItems(
185 sorted(self.__venvManager.getVirtualenvNames()))
186 index = self.venvComboBox.findText(currentText)
187 if index < 0:
188 index = 0
189 self.venvComboBox.setCurrentIndex(index)
167 190
168 def __setProgressColor(self, color): 191 def __setProgressColor(self, color):
169 """ 192 """
170 Private methode to set the color of the progress color label. 193 Private methode to set the color of the progress color label.
171 194
262 defaultDirectory = os.path.expanduser("~") 285 defaultDirectory = os.path.expanduser("~")
263 if self.__dbs: 286 if self.__dbs:
264 project = e5App().getObject("Project") 287 project = e5App().getObject("Project")
265 if self.__forProject and project.isOpen(): 288 if self.__forProject and project.isOpen():
266 defaultDirectory = project.getProjectPath() 289 defaultDirectory = project.getProjectPath()
290 self.testsuitePicker.setDefaultDirectory(defaultDirectory)
267 291
268 @pyqtSlot(str) 292 @pyqtSlot(str)
269 def on_testsuitePicker_pathSelected(self, suite): 293 def on_testsuitePicker_pathSelected(self, suite):
270 """ 294 """
271 Private slot called after a test suite has been selected. 295 Private slot called after a test suite has been selected.
301 Private slot called by a button of the button box clicked. 325 Private slot called by a button of the button box clicked.
302 326
303 @param button button that was clicked (QAbstractButton) 327 @param button button that was clicked (QAbstractButton)
304 """ 328 """
305 if button == self.startButton: 329 if button == self.startButton:
306 self.on_startButton_clicked() 330 self.startTests()
307 elif button == self.stopButton: 331 elif button == self.stopButton:
308 self.on_stopButton_clicked() 332 self.__stopTests()
309 elif button == self.startFailedButton: 333 elif button == self.startFailedButton:
310 self.on_startButton_clicked(failedOnly=True) 334 self.startTests(failedOnly=True)
311 335
312 @pyqtSlot() 336 @pyqtSlot()
313 def on_startButton_clicked(self, failedOnly=False): 337 def startTests(self, failedOnly=False):
314 """ 338 """
315 Private slot to start the test. 339 Public slot to start the test.
316 340
317 @keyparam failedOnly flag indicating to run only failed tests (boolean) 341 @keyparam failedOnly flag indicating to run only failed tests (boolean)
318 """ 342 """
343 # TODO: run only failed test ignoring test parameters when failedOnly is set
319 if self.running: 344 if self.running:
320 return 345 return
321 346
322 discover = self.discoverCheckBox.isChecked() 347 discover = self.discoverCheckBox.isChecked()
323 if discover: 348 if discover:
324 discoveryStart = self.discoveryPicker.currentText() 349 discoveryStart = self.discoveryPicker.currentText()
325 prog = "" 350 testFileName = ""
351 testName = ""
326 else: 352 else:
327 discoveryStart = "" 353 discoveryStart = ""
328 prog = self.testsuitePicker.currentText() 354 testFileName = self.testsuitePicker.currentText()
329 355 testName = self.testComboBox.currentText()
330 if not prog and not discover: 356 if testName:
357 self.insertTestName(testName)
358 if testFileName and not testName:
359 testName = "suite"
360
361 if not discover and not testFileName and not testName:
331 E5MessageBox.critical( 362 E5MessageBox.critical(
332 self, 363 self,
333 self.tr("Unittest"), 364 self.tr("Unittest"),
334 self.tr("You must enter a test suite file or select" 365 self.tr("You must select auto-discovery or enter a test suite"
335 " auto-discovery.")) 366 " file or a dotted test name."))
336 return 367 return
337 368
338 # prepend the selected file to the testsuite combobox 369 # prepend the selected file to the testsuite combobox
339 self.insertProg(prog) 370 self.insertProg(testFileName)
340 self.sbLabel.setText(self.tr("Preparing Testsuite")) 371 self.sbLabel.setText(self.tr("Preparing Testsuite"))
341 QApplication.processEvents() 372 QApplication.processEvents()
342 373
343 if discover: 374 if discover:
344 testFunctionName = ""
345 self.testName = self.tr("Unittest with auto-discovery") 375 self.testName = self.tr("Unittest with auto-discovery")
346 else: 376 else:
347 testFunctionName = self.testComboBox.currentText() 377 # build the module name from the filename without extension
348 if testFunctionName: 378 if testFileName:
349 self.insertTestName(testFunctionName) 379 self.testName = os.path.splitext(
380 os.path.basename(testFileName))[0]
381 elif testName:
382 self.testName = testName
350 else: 383 else:
351 testFunctionName = "suite" 384 self.testName = self.tr("<Unnamed Test>")
385
386 if self.__dbs:
387 venvName = self.venvComboBox.currentText()
352 388
353 # build the module name from the filename without extension
354 self.testName = os.path.splitext(os.path.basename(prog))[0]
355
356 if self.__dbs:
357 # we are cooperating with the eric6 IDE 389 # we are cooperating with the eric6 IDE
358 project = e5App().getObject("Project") 390 project = e5App().getObject("Project")
359 if self.__forProject and project.isOpen() and \ 391 if self.__forProject:
360 (discover or project.isProjectSource(prog)):
361 mainScript = os.path.abspath(project.getMainScript(True)) 392 mainScript = os.path.abspath(project.getMainScript(True))
362 clientType = project.getProjectLanguage() 393 clientType = project.getProjectLanguage()
363 if mainScript: 394 if mainScript:
364 workdir = os.path.dirname(mainScript) 395 workdir = os.path.dirname(mainScript)
365 else: 396 else:
366 workdir = project.getProjectPath() 397 workdir = project.getProjectPath()
367 sysPath = [workdir] 398 sysPath = [workdir]
399 coverageFile = os.path.splitext(mainScript)[0]
368 if discover and not discoveryStart: 400 if discover and not discoveryStart:
369 discoveryStart = workdir 401 discoveryStart = workdir
370 else: 402 else:
371 if discover: 403 if discover:
372 if not discoveryStart: 404 if not discoveryStart:
374 self, 406 self,
375 self.tr("Unittest"), 407 self.tr("Unittest"),
376 self.tr("You must enter a start directory for" 408 self.tr("You must enter a start directory for"
377 " auto-discovery.")) 409 " auto-discovery."))
378 return 410 return
379 mainScript = os.path.join(discoveryStart, "unittest") 411
412 coverageFile = os.path.join(discoveryStart, "unittest")
380 workdir = "" 413 workdir = ""
381 # assume Python3 for auto-discovery 414 clientType = \
382 clientType = "Python3" 415 self.__venvManager.getVirtualenvVariant(venvName)
383 else: 416 if not clientType:
384 mainScript = os.path.abspath(prog) 417 # assume Python 3
418 clientType = "Python3"
419 elif testFileName:
420 mainScript = os.path.abspath(testFileName)
421 flags = Utilities.extractFlagsFromFile(mainScript)
385 workdir = os.path.dirname(mainScript) 422 workdir = os.path.dirname(mainScript)
386 flags = Utilities.extractFlagsFromFile(mainScript)
387 if mainScript.endswith( 423 if mainScript.endswith(
388 tuple(Preferences.getPython("PythonExtensions"))) or \ 424 tuple(Preferences.getPython("PythonExtensions"))) or \
389 ("FileType" in flags and 425 ("FileType" in flags and
390 flags["FileType"] in ["Python", "Python2"]): 426 flags["FileType"] in ["Python", "Python2"]):
391 clientType = "Python2" 427 clientType = "Python2"
392 else: 428 else:
393 # if it is not Python2 it must be Python3! 429 # if it is not Python2 it must be Python3!
394 clientType = "Python3" 430 clientType = "Python3"
431 coverageFile = os.path.splitext(mainScript)[0]
432 else:
433 coverageFile = os.path.abspath("unittest")
434 workdir = ""
435 clientType = \
436 self.__venvManager.getVirtualenvVariant(venvName)
437 if not clientType:
438 # assume Python 3
439 clientType = "Python3"
395 sysPath = [] 440 sysPath = []
396 if not discover and failedOnly and self.__failedTests: 441 if not discover and failedOnly and self.__failedTests:
397 failed = [t.split(".", 1)[1] for t in self.__failedTests] 442 failed = self.__failedTests[:]
398 else: 443 else:
399 failed = [] 444 failed = []
400 self.__failedTests = [] 445 self.__failedTests = []
401 self.__dbs.remoteUTPrepare( 446 self.__dbs.remoteUTPrepare(
402 prog, self.testName, testFunctionName, failed, 447 testFileName, self.testName, testName, failed,
403 self.coverageCheckBox.isChecked(), mainScript, 448 self.coverageCheckBox.isChecked(), coverageFile,
404 self.coverageEraseCheckBox.isChecked(), clientType=clientType, 449 self.coverageEraseCheckBox.isChecked(), clientType=clientType,
405 forProject=self.__forProject, workdir=workdir, 450 forProject=self.__forProject, workdir=workdir,
406 venvName=self.venvComboBox.currentText(), syspath=sysPath, 451 venvName=venvName, syspath=sysPath,
407 discover=discover, discoveryStart=discoveryStart) 452 discover=discover, discoveryStart=discoveryStart)
408 else: 453 else:
409 # TODO: add discovery
410 # we are running as an application 454 # we are running as an application
411 sys.path = [os.path.dirname(os.path.abspath(prog))] + \ 455 if testFileName:
412 self.savedSysPath 456 sys.path = [os.path.dirname(os.path.abspath(testFileName))] + \
457 self.savedSysPath
413 458
414 # clean up list of imported modules to force a reimport upon 459 # clean up list of imported modules to force a reimport upon
415 # running the test 460 # running the test
416 if self.savedModulelist: 461 if self.savedModulelist:
417 for modname in list(sys.modules.keys()): 462 for modname in list(sys.modules.keys()):
430 self.tr("You must enter a start directory for" 475 self.tr("You must enter a start directory for"
431 " auto-discovery.")) 476 " auto-discovery."))
432 return 477 return
433 478
434 test = unittest.defaultTestLoader.discover(discoveryStart) 479 test = unittest.defaultTestLoader.discover(discoveryStart)
480 # testsList = self.__assembleTestCasesList(test)
435 else: 481 else:
436 module = __import__(self.testName) 482 if testFileName:
437 try: 483 module = __import__(self.testName)
438 if failedOnly and self.__failedTests: 484 else:
439 test = \ 485 module = None
440 unittest.defaultTestLoader.loadTestsFromNames( 486 if failedOnly and self.__failedTests:
441 [t.split(".", 1)[1] 487 if module:
442 for t in self.__failedTests], 488 failed = [t.split(".", 1)[1]
443 module) 489 for t in self.__failedTests]
444 else: 490 else:
445 test = \ 491 failed = self.__failedTests[:]
446 unittest.defaultTestLoader.loadTestsFromName( 492 test = unittest.defaultTestLoader.loadTestsFromNames(
447 testFunctionName, module) 493 failed, module)
448 except AttributeError: 494 else:
449 test = unittest.defaultTestLoader.loadTestsFromModule( 495 test = unittest.defaultTestLoader.loadTestsFromName(
450 module) 496 testName, module)
451 except Exception: 497 except Exception:
452 exc_type, exc_value, exc_tb = sys.exc_info() 498 exc_type, exc_value, exc_tb = sys.exc_info()
453 E5MessageBox.critical( 499 E5MessageBox.critical(
454 self, 500 self,
455 self.tr("Unittest"), 501 self.tr("Unittest"),
462 508
463 # now set up the coverage stuff 509 # now set up the coverage stuff
464 if self.coverageCheckBox.isChecked(): 510 if self.coverageCheckBox.isChecked():
465 if discover: 511 if discover:
466 covname = os.path.join(discoveryStart, "unittest") 512 covname = os.path.join(discoveryStart, "unittest")
467 elif prog: 513 elif testFileName:
468 covname = os.path.splitext(os.path.abspath(prog))[0] 514 covname = \
515 os.path.splitext(os.path.abspath(testFileName))[0]
469 else: 516 else:
470 covname = "unittest" 517 covname = "unittest"
471 518
472 from DebugClients.Python.coverage import coverage 519 from DebugClients.Python.coverage import coverage
473 cover = coverage(data_file="{0}.coverage".format(covname)) 520 cover = coverage(data_file="{0}.coverage".format(covname))
487 cover.stop() 534 cover.stop()
488 cover.save() 535 cover.save()
489 self.__setStoppedMode() 536 self.__setStoppedMode()
490 sys.path = self.savedSysPath 537 sys.path = self.savedSysPath
491 538
539 def __assembleTestCasesList(self, suite):
540 """
541 Private method to assemble a list of test cases included in a test
542 suite.
543
544 @param suite test suite to be inspected
545 @type unittest.TestSuite
546 @return list of tuples containing the test case ID and short
547 description
548 @rtype list of tuples of (str, str)
549 """
550 testCases = []
551 for test in suite:
552 if isinstance(test, unittest.TestSuite):
553 testCases.extend(self.__assembleTestCasesList(test))
554 else:
555 testCases.append((test.id(), test.shortDescription()))
556 return testCases
557
492 def __UTPrepared(self, nrTests, exc_type, exc_value): 558 def __UTPrepared(self, nrTests, exc_type, exc_value):
493 """ 559 """
494 Private slot to handle the utPrepared signal. 560 Private slot to handle the utPrepared signal.
495 561
496 If the unittest suite was loaded successfully, we ask the 562 If the unittest suite was loaded successfully, we ask the
512 self.totalTests = nrTests 578 self.totalTests = nrTests
513 self.__setRunningMode() 579 self.__setRunningMode()
514 self.__dbs.remoteUTRun() 580 self.__dbs.remoteUTRun()
515 581
516 @pyqtSlot() 582 @pyqtSlot()
517 def on_stopButton_clicked(self): 583 def __stopTests(self):
518 """ 584 """
519 Private slot to stop the test. 585 Private slot to stop the test.
520 """ 586 """
521 if self.__dbs: 587 if self.__dbs:
522 self.__dbs.remoteUTStop() 588 self.__dbs.remoteUTStop()
923 self.setCentralWidget(self.cw) 989 self.setCentralWidget(self.cw)
924 self.resize(size) 990 self.resize(size)
925 991
926 self.setStyle(Preferences.getUI("Style"), 992 self.setStyle(Preferences.getUI("Style"),
927 Preferences.getUI("StyleSheet")) 993 Preferences.getUI("StyleSheet"))
994
995 self.cw.buttonBox.accepted.connect(self.close)
996 self.cw.buttonBox.rejected.connect(self.close)
928 997
929 def eventFilter(self, obj, event): 998 def eventFilter(self, obj, event):
930 """ 999 """
931 Public method to filter events. 1000 Public method to filter events.
932 1001

eric ide

mercurial