PyUnit/UnittestDialog.py

changeset 6894
df83ac87e0db
parent 6893
d29a7b8fab0f
child 6896
3716c4af48bb
equal deleted inserted replaced
6893:d29a7b8fab0f 6894:df83ac87e0db
66 self.setupUi(self) 66 self.setupUi(self)
67 67
68 self.testsuitePicker.setMode(E5PathPickerModes.OpenFileMode) 68 self.testsuitePicker.setMode(E5PathPickerModes.OpenFileMode)
69 self.testsuitePicker.setInsertPolicy(QComboBox.InsertAtTop) 69 self.testsuitePicker.setInsertPolicy(QComboBox.InsertAtTop)
70 self.testsuitePicker.setSizeAdjustPolicy( 70 self.testsuitePicker.setSizeAdjustPolicy(
71 QComboBox.AdjustToMinimumContentsLength)
72
73 self.discoveryPicker.setMode(E5PathPickerModes.DirectoryMode)
74 self.discoveryPicker.setInsertPolicy(QComboBox.InsertAtTop)
75 self.discoveryPicker.setSizeAdjustPolicy(
71 QComboBox.AdjustToMinimumContentsLength) 76 QComboBox.AdjustToMinimumContentsLength)
72 77
73 self.startButton = self.buttonBox.addButton( 78 self.startButton = self.buttonBox.addButton(
74 self.tr("Start"), QDialogButtonBox.ActionRole) 79 self.tr("Start"), QDialogButtonBox.ActionRole)
75 self.startButton.setToolTip(self.tr( 80 self.startButton.setToolTip(self.tr(
103 Qt.WindowContextHelpButtonHint)) 108 Qt.WindowContextHelpButtonHint))
104 self.setWindowIcon(UI.PixmapCache.getIcon("eric.png")) 109 self.setWindowIcon(UI.PixmapCache.getIcon("eric.png"))
105 self.setWindowTitle(self.tr("Unittest")) 110 self.setWindowTitle(self.tr("Unittest"))
106 if dbs: 111 if dbs:
107 self.ui = ui 112 self.ui = ui
113
114 self.venvComboBox.addItem("")
115 self.venvComboBox.addItems(
116 sorted(e5App().getObject("VirtualEnvManager")
117 .getVirtualenvNames()))
118 self.venvComboBox.setVisible(bool(self.__dbs))
119 self.venvLabel.setVisible(bool(self.__dbs))
120
108 self.__setProgressColor("green") 121 self.__setProgressColor("green")
109 self.progressLed.setDarkFactor(150) 122 self.progressLed.setDarkFactor(150)
110 self.progressLed.off() 123 self.progressLed.off()
111 124
112 self.venvComboBox.addItem("") 125 self.discoverHistory = []
113 self.venvComboBox.addItems(
114 sorted(e5App().getObject("VirtualEnvManager")
115 .getVirtualenvNames()))
116 self.venvComboBox.setEnabled(bool(self.__dbs))
117
118 self.fileHistory = [] 126 self.fileHistory = []
119 self.testNameHistory = [] 127 self.testNameHistory = []
120 self.running = False 128 self.running = False
121 self.savedModulelist = None 129 self.savedModulelist = None
122 self.savedSysPath = sys.path 130 self.savedSysPath = sys.path
171 179
172 @param forProject flag indicating to run for the open project 180 @param forProject flag indicating to run for the open project
173 @type bool 181 @type bool
174 """ 182 """
175 self.__forProject = forProject 183 self.__forProject = forProject
184 if forProject:
185 project = e5App().getObject("Project")
186 if project.isOpen():
187 self.insertDiscovery(project.getProjectPath())
188 else:
189 self.insertDiscovery("")
190 else:
191 self.insertDiscovery("")
192
193 def insertDiscovery(self, start):
194 """
195 Public slot to insert the discovery start directory into the
196 discoveryPicker object.
197
198 @param start start directory name to be inserted
199 @type str
200 """
201 # prepend the given directory to the discovery picker
202 if start is None:
203 start = ""
204 if start in self.discoverHistory:
205 self.discoverHistory.remove(start)
206 self.discoverHistory.insert(0, start)
207 self.discoveryPicker.clear()
208 self.discoveryPicker.addItems(self.discoverHistory)
176 209
177 def insertProg(self, prog): 210 def insertProg(self, prog):
178 """ 211 """
179 Public slot to insert the filename prog into the testsuitePicker 212 Public slot to insert the filename prog into the testsuitePicker
180 object. 213 object.
240 @param suite file name of the test suite 273 @param suite file name of the test suite
241 @type str 274 @type str
242 """ 275 """
243 self.insertProg(suite) 276 self.insertProg(suite)
244 277
278 @pyqtSlot(str)
279 def on_testsuitePicker_editTextChanged(self, path):
280 """
281 Private slot handling changes of the test suite path.
282
283 @param path path of the test suite file
284 @type str
285 """
286 self.startFailedButton.setEnabled(False)
287
288 @pyqtSlot(bool)
289 def on_discoverCheckBox_toggled(self, checked):
290 """
291 Private slot handling state changes of the 'discover' checkbox.
292
293 @param checked state of the checkbox
294 @type bool
295 """
296 self.startFailedButton.setEnabled(
297 bool(self.__failedTests) and not checked)
298
245 def on_buttonBox_clicked(self, button): 299 def on_buttonBox_clicked(self, button):
246 """ 300 """
247 Private slot called by a button of the button box clicked. 301 Private slot called by a button of the button box clicked.
248 302
249 @param button button that was clicked (QAbstractButton) 303 @param button button that was clicked (QAbstractButton)
263 @keyparam failedOnly flag indicating to run only failed tests (boolean) 317 @keyparam failedOnly flag indicating to run only failed tests (boolean)
264 """ 318 """
265 if self.running: 319 if self.running:
266 return 320 return
267 321
268 prog = self.testsuitePicker.currentText() 322 discover = self.discoverCheckBox.isChecked()
269 if not prog: 323 if discover:
324 discoveryStart = self.discoveryPicker.currentText()
325 prog = ""
326 else:
327 discoveryStart = ""
328 prog = self.testsuitePicker.currentText()
329
330 if not prog and not discover:
270 E5MessageBox.critical( 331 E5MessageBox.critical(
271 self, 332 self,
272 self.tr("Unittest"), 333 self.tr("Unittest"),
273 self.tr("You must enter a test suite file.")) 334 self.tr("You must enter a test suite file or select"
335 " auto-discovery."))
274 return 336 return
275 337
276 # prepend the selected file to the testsuite combobox 338 # prepend the selected file to the testsuite combobox
277 self.insertProg(prog) 339 self.insertProg(prog)
278 self.sbLabel.setText(self.tr("Preparing Testsuite")) 340 self.sbLabel.setText(self.tr("Preparing Testsuite"))
279 QApplication.processEvents() 341 QApplication.processEvents()
280 342
281 testFunctionName = self.testComboBox.currentText() 343 if discover:
282 if testFunctionName: 344 testFunctionName = ""
283 self.insertTestName(testFunctionName) 345 self.testName = self.tr("Unittest with auto-discovery")
284 else: 346 else:
285 testFunctionName = "suite" 347 testFunctionName = self.testComboBox.currentText()
286 348 if testFunctionName:
287 # build the module name from the filename without extension 349 self.insertTestName(testFunctionName)
288 self.testName = os.path.splitext(os.path.basename(prog))[0] 350 else:
351 testFunctionName = "suite"
352
353 # build the module name from the filename without extension
354 self.testName = os.path.splitext(os.path.basename(prog))[0]
289 355
290 if self.__dbs: 356 if self.__dbs:
291 # we are cooperating with the eric6 IDE 357 # we are cooperating with the eric6 IDE
292 project = e5App().getObject("Project") 358 project = e5App().getObject("Project")
293 if self.__forProject and project.isOpen() and \ 359 if self.__forProject and project.isOpen() and \
294 project.isProjectSource(prog): 360 (discover or project.isProjectSource(prog)):
295 mainScript = os.path.abspath(project.getMainScript(True)) 361 mainScript = os.path.abspath(project.getMainScript(True))
296 clientType = project.getProjectLanguage() 362 clientType = project.getProjectLanguage()
297 sysPath = [os.path.dirname(mainScript)] 363 if mainScript:
364 workdir = os.path.dirname(mainScript)
365 else:
366 workdir = project.getProjectPath()
367 sysPath = [workdir]
368 if discover and not discoveryStart:
369 discoveryStart = workdir
298 else: 370 else:
299 mainScript = os.path.abspath(prog) 371 if discover:
372 if not discoveryStart:
373 E5MessageBox.critical(
374 self,
375 self.tr("Unittest"),
376 self.tr("You must enter a start directory for"
377 " auto-discovery."))
378 return
379 mainScript = os.path.join(discoveryStart, "unittest")
380 workdir = ""
381 # assume Python3 for auto-discovery
382 clientType = "Python3"
383 else:
384 mainScript = os.path.abspath(prog)
385 workdir = os.path.dirname(mainScript)
386 flags = Utilities.extractFlagsFromFile(mainScript)
387 if mainScript.endswith(
388 tuple(Preferences.getPython("PythonExtensions"))) or \
389 ("FileType" in flags and
390 flags["FileType"] in ["Python", "Python2"]):
391 clientType = "Python2"
392 else:
393 # if it is not Python2 it must be Python3!
394 clientType = "Python3"
300 sysPath = [] 395 sysPath = []
301 flags = Utilities.extractFlagsFromFile(mainScript) 396 if not discover and failedOnly and self.__failedTests:
302 if mainScript.endswith(
303 tuple(Preferences.getPython("PythonExtensions"))) or \
304 ("FileType" in flags and
305 flags["FileType"] in ["Python", "Python2"]):
306 clientType = "Python2"
307 else:
308 # if it is not Python2 it must be Python3!
309 clientType = "Python3"
310 if failedOnly and self.__failedTests:
311 failed = [t.split(".", 1)[1] for t in self.__failedTests] 397 failed = [t.split(".", 1)[1] for t in self.__failedTests]
312 else: 398 else:
313 failed = [] 399 failed = []
314 self.__failedTests = [] 400 self.__failedTests = []
315 self.__dbs.remoteUTPrepare( 401 self.__dbs.remoteUTPrepare(
316 prog, self.testName, testFunctionName, failed, 402 prog, self.testName, testFunctionName, failed,
317 self.coverageCheckBox.isChecked(), mainScript, 403 self.coverageCheckBox.isChecked(), mainScript,
318 self.coverageEraseCheckBox.isChecked(), clientType=clientType, 404 self.coverageEraseCheckBox.isChecked(), clientType=clientType,
319 forProject=self.__forProject, 405 forProject=self.__forProject, workdir=workdir,
320 venvName=self.venvComboBox.currentText(), syspath=sysPath) 406 venvName=self.venvComboBox.currentText(), syspath=sysPath,
407 discover=discover, discoveryStart=discoveryStart)
321 else: 408 else:
409 # TODO: add discovery
322 # we are running as an application 410 # we are running as an application
323 sys.path = [os.path.dirname(os.path.abspath(prog))] + \ 411 sys.path = [os.path.dirname(os.path.abspath(prog))] + \
324 self.savedSysPath 412 self.savedSysPath
325 413
326 # clean up list of imported modules to force a reimport upon 414 # clean up list of imported modules to force a reimport upon
332 del(sys.modules[modname]) 420 del(sys.modules[modname])
333 self.savedModulelist = sys.modules.copy() 421 self.savedModulelist = sys.modules.copy()
334 422
335 # now try to generate the testsuite 423 # now try to generate the testsuite
336 try: 424 try:
337 module = __import__(self.testName) 425 if discover:
338 try: 426 if not discoveryStart:
339 if failedOnly and self.__failedTests: 427 E5MessageBox.critical(
340 test = unittest.defaultTestLoader.loadTestsFromNames( 428 self,
341 [t.split(".", 1)[1] for t in self.__failedTests], 429 self.tr("Unittest"),
430 self.tr("You must enter a start directory for"
431 " auto-discovery."))
432 return
433
434 test = unittest.defaultTestLoader.discover(discoveryStart)
435 else:
436 module = __import__(self.testName)
437 try:
438 if failedOnly and self.__failedTests:
439 test = \
440 unittest.defaultTestLoader.loadTestsFromNames(
441 [t.split(".", 1)[1]
442 for t in self.__failedTests],
443 module)
444 else:
445 test = \
446 unittest.defaultTestLoader.loadTestsFromName(
447 testFunctionName, module)
448 except AttributeError:
449 test = unittest.defaultTestLoader.loadTestsFromModule(
342 module) 450 module)
343 else:
344 test = unittest.defaultTestLoader.loadTestsFromName(
345 testFunctionName, module)
346 except AttributeError:
347 test = unittest.defaultTestLoader.loadTestsFromModule(
348 module)
349 except Exception: 451 except Exception:
350 exc_type, exc_value, exc_tb = sys.exc_info() 452 exc_type, exc_value, exc_tb = sys.exc_info()
351 E5MessageBox.critical( 453 E5MessageBox.critical(
352 self, 454 self,
353 self.tr("Unittest"), 455 self.tr("Unittest"),
358 str(exc_value))) 460 str(exc_value)))
359 return 461 return
360 462
361 # now set up the coverage stuff 463 # now set up the coverage stuff
362 if self.coverageCheckBox.isChecked(): 464 if self.coverageCheckBox.isChecked():
363 if self.__dbs: 465 if discover:
364 # we are cooperating with the eric6 IDE 466 covname = os.path.join(discoveryStart, "unittest")
365 project = e5App().getObject("Project") 467 elif prog:
366 if project.isOpen() and project.isProjectSource(prog): 468 covname = os.path.splitext(os.path.abspath(prog))[0]
367 mainScript = project.getMainScript(True)
368 if not mainScript:
369 mainScript = os.path.abspath(prog)
370 else:
371 mainScript = os.path.abspath(prog)
372 else: 469 else:
373 mainScript = os.path.abspath(prog) 470 covname = "unittest"
374 471
375 from DebugClients.Python.coverage import coverage 472 from DebugClients.Python.coverage import coverage
376 cover = coverage( 473 cover = coverage(data_file="{0}.coverage".format(covname))
377 data_file="{0}.coverage".format(
378 os.path.splitext(mainScript)[0]))
379 if self.coverageEraseCheckBox.isChecked(): 474 if self.coverageEraseCheckBox.isChecked():
380 cover.erase() 475 cover.erase()
381 else: 476 else:
382 cover = None 477 cover = None
383 478
411 self.tr("Unittest"), 506 self.tr("Unittest"),
412 self.tr( 507 self.tr(
413 "<p>Unable to run test <b>{0}</b>.<br>{1}<br>{2}</p>") 508 "<p>Unable to run test <b>{0}</b>.<br>{1}<br>{2}</p>")
414 .format(self.testName, exc_type, exc_value)) 509 .format(self.testName, exc_type, exc_value))
415 return 510 return
416 511
417 self.totalTests = nrTests 512 self.totalTests = nrTests
418 self.__setRunningMode() 513 self.__setRunningMode()
419 self.__dbs.remoteUTRun() 514 self.__dbs.remoteUTRun()
420 515
421 @pyqtSlot() 516 @pyqtSlot()
448 def __setRunningMode(self): 543 def __setRunningMode(self):
449 """ 544 """
450 Private method to set the GUI in running mode. 545 Private method to set the GUI in running mode.
451 """ 546 """
452 self.running = True 547 self.running = True
548 self.tabWidget.setCurrentIndex(1)
453 549
454 # reset counters and error infos 550 # reset counters and error infos
455 self.runCount = 0 551 self.runCount = 0
456 self.failCount = 0 552 self.failCount = 0
457 self.errorCount = 0 553 self.errorCount = 0
468 self.progressCounterSkippedCount.setText(str(self.skippedCount)) 564 self.progressCounterSkippedCount.setText(str(self.skippedCount))
469 self.progressCounterExpectedFailureCount.setText( 565 self.progressCounterExpectedFailureCount.setText(
470 str(self.expectedFailureCount)) 566 str(self.expectedFailureCount))
471 self.progressCounterUnexpectedSuccessCount.setText( 567 self.progressCounterUnexpectedSuccessCount.setText(
472 str(self.unexpectedSuccessCount)) 568 str(self.unexpectedSuccessCount))
569
473 self.errorsListWidget.clear() 570 self.errorsListWidget.clear()
474 self.testsListWidget.clear() 571 self.testsListWidget.clear()
572
475 self.progressProgressBar.setRange(0, self.totalTests) 573 self.progressProgressBar.setRange(0, self.totalTests)
476 self.__setProgressColor("green") 574 self.__setProgressColor("green")
477 self.progressProgressBar.reset() 575 self.progressProgressBar.reset()
576
478 self.stopButton.setEnabled(True) 577 self.stopButton.setEnabled(True)
479 self.startButton.setEnabled(False) 578 self.startButton.setEnabled(False)
579 self.startFailedButton.setEnabled(False)
480 self.stopButton.setDefault(True) 580 self.stopButton.setDefault(True)
581
481 self.sbLabel.setText(self.tr("Running")) 582 self.sbLabel.setText(self.tr("Running"))
482 self.progressLed.on() 583 self.progressLed.on()
483 QApplication.processEvents() 584 QApplication.processEvents()
484 585
485 self.startTime = time.time() 586 self.startTime = time.time()
490 """ 591 """
491 self.stopTime = time.time() 592 self.stopTime = time.time()
492 self.timeTaken = float(self.stopTime - self.startTime) 593 self.timeTaken = float(self.stopTime - self.startTime)
493 self.running = False 594 self.running = False
494 595
596 failedAvailable = bool(self.__failedTests) and \
597 not self.discoverCheckBox.isChecked()
495 self.startButton.setEnabled(True) 598 self.startButton.setEnabled(True)
496 self.startFailedButton.setEnabled(bool(self.__failedTests)) 599 self.startFailedButton.setEnabled(failedAvailable)
497 self.stopButton.setEnabled(False) 600 self.stopButton.setEnabled(False)
498 if self.__failedTests: 601 if failedAvailable:
499 self.startFailedButton.setDefault(True) 602 self.startFailedButton.setDefault(True)
500 self.startButton.setDefault(False) 603 self.startButton.setDefault(False)
501 else: 604 else:
502 self.startFailedButton.setDefault(False) 605 self.startFailedButton.setDefault(False)
503 self.startButton.setDefault(True) 606 self.startButton.setDefault(True)
504 if self.runCount == 1: 607 self.sbLabel.setText(
505 self.sbLabel.setText( 608 self.tr("Ran %n test(s) in {0:.3f}s", "", self.runCount)
506 self.tr("Ran {0} test in {1:.3f}s") 609 .format(self.timeTaken))
507 .format(self.runCount, self.timeTaken))
508 else:
509 self.sbLabel.setText(
510 self.tr("Ran {0} tests in {1:.3f}s")
511 .format(self.runCount, self.timeTaken))
512 self.progressLed.off() 610 self.progressLed.off()
513 611
514 self.unittestStopped.emit() 612 self.unittestStopped.emit()
515 613
516 def testFailed(self, test, exc, testId): 614 def testFailed(self, test, exc, testId):

eric ide

mercurial