Python 我应该如何测试不返回任何内容的方法?
这是我最近制作的工具中的代码,我正在尝试编写unittest,我有一个测试方法,但不知道应该如何测试,不喜欢下面的方法:Python 我应该如何测试不返回任何内容的方法?,python,unit-testing,testing,ui-testing,Python,Unit Testing,Testing,Ui Testing,这是我最近制作的工具中的代码,我正在尝试编写unittest,我有一个测试方法,但不知道应该如何测试,不喜欢下面的方法: def buildUi(self): self.label = QtGui.QLabel() self.label.setAlignment(QtCore.Qt.AlignCenter) self.setCentralWidget(self.label) def nextImage(self): """ switch to next imag
def buildUi(self):
self.label = QtGui.QLabel()
self.label.setAlignment(QtCore.Qt.AlignCenter)
self.setCentralWidget(self.label)
def nextImage(self):
""" switch to next image or previous image
"""
if self._imagesInList:
if self._count == len(self._imagesInList):
self._count = 0
self.showImageByPath(
self._imagesInList[self._count])
if self.animFlag:
self._count += 1
else:
self._count -= 1
def showImageByPath(self, path):
if path:
image = QtGui.QImage(path)
pp = QtGui.QPixmap.fromImage(image)
self.label.setPixmap(pp.scaled(
self.label.size(),
QtCore.Qt.KeepAspectRatio,
QtCore.Qt.SmoothTransformation))
def playPause(self):
if not self._pause:
self._pause = True
self.updateTimer.start(2500)
return self._pause
else:
self._pause = False
self.updateTimer.stop()
def keyPressEvent(self, keyevent):
""" Capture key to exit, next image, previous image,
on Escape , Key Right and key left respectively.
"""
event = keyevent.key()
if event == QtCore.Qt.Key_Escape:
self.close()
if event == QtCore.Qt.Key_Left:
self.animFlag = False
self.nextImage()
if event == QtCore.Qt.Key_Right:
self.animFlag = True
self.nextImage()
if event == 32:
self._pause = self.playPause()
可以找到查找的完整代码
是否有可能测试上述这些方法,或者我是否必须修改以使其可测试?
编辑:更新:
class TestSlideShow(unittest.TestCase):
""" docstring for TestSlideShow
"""
def setUp(self):
self.mox = mox.Mox()
self.imgLst = ['/folder/test/images/test1.jpg', '/folder/test/images/test2.JPG',
'/folder/test/images/test3.png', '/folder/test/images/test4.PNG']
app = QtGui.QApplication([])
self.show = slideShow.SlideShowPics(imgLst=self.imgLst, ui=False)
def tearDown(self):
self.mox.UnsetStubs()
self.mox.ResetAll()
def test_nextImage(self):
self.mox.StubOutWithMock(self.show, 'prepairWindow')
self.show.prepairWindow()
self.mox.StubOutWithMock(self.show, 'showImageByPath')
self.show.showImageByPath(self.imgLst[1])
self.show.nextImage()
# self.mox.ReplayAll()
self.assertEquals(1, self.show.count)
self.assertEquals(self.imgLst[1], self.show._imagesInList[1])
# self.mox.VerifyAll()
def test_nextImage_animFlag_False(self):
self.show.animFlag = False
self.show.count = 4
self.mox.StubOutWithMock(self.show, 'prepairWindow')
self.show.prepairWindow()
self.mox.StubOutWithMock(self.show, 'showImageByPath')
self.show.showImageByPath(self.imgLst[3])
print self.show.count
self.show.nextImage()
print self.show.count
# self.assertEquals(3, self.show.count)
self.assertEquals(self.imgLst[3], self.show._imagesInList[3])
if __name__ == '__main__':
unittest.main()
当self.show.animFlag为True时,第一个测试可以正常工作,但是当我手动设置animFlag=False时,第二个测试失败。这就是在代码之后编写unittest的问题-然后您就会意识到您的代码很难测试。在编写代码之前编写测试(好吧,真正“沿着”代码——在开始编写代码之前,您不会编写所有测试,但在测试之前,您仍然不会编写一行代码)可以确保您不会遇到这样的问题 现在,即使使用“测试优先”方法,您也必须测试不返回任何内容的方法。这样做的方法是测试预期的副作用。其中一些副作用很容易测试-在上述情况下,您可以在调用
nextImage
之前和之后测试self.\u count
的值,具体取决于对象的状态(\u imagesInList
和animfag
)。更困难的是,如果您想测试nextImage
是否确实使用正确的参数调用了showmagebypath
,而对于您当前的设计,唯一的方法就是使用monkeypatchshowmagebypath
进行测试。测试showImageByPath将需要修补/模拟self.label.setPixmap()
等
正如其他人已经指出的那样,有几个mock/stub lib可以提供帮助,但它们不能解决所有可能的可测试性问题,您可能需要重新考虑您的设计以使事情变得更简单—比如不在
buildUI()
中硬编码对QtGui.QLabel()的调用,但可以通过某种方式“注入”所需的组件(QtGui.QLabel()
或mock)。作为一般规则,可测试代码很少有硬编码依赖项,很少有副作用,并且有很多小类使用短方法(而不是使用长方法的大类)。尽管函数不返回任何内容,但它们实际上会执行一些操作;)这就是您要测试的内容。您创建一个对象(例如,一个模拟对象),调用影响该对象的函数,然后检查它,并检查是否一切正常。查看模拟和存根@User:I想使用mox进行操作。@septi您能给我举个例子吗?我可以在nextImage
中模拟showmagebypath
,但是,我不明白您在buildUI()中不硬编码对QtGui.QLabel()的调用是什么意思,以及“副作用”一词在测试中指的是什么?@san函数的副作用是它以返回值以外的方式更改程序状态的方式。例如,def():全局x;x+=1;返回x*5
会产生将1添加到x
的副作用。在Python中最好避免它们。@san:wrt/sideeffects,我主要考虑的是您的方法确实会更改实例的状态或生成对象或调用其他对象方法等。如果一个方法应该以给定的方式更改对象的状态,您可以测试对象的状态是否与方法调用后所期望的状态一致。@san:wrt/harcoding,它简单明了:组件名QtGui.QLabel
在buildUI
中是用普通字母写的,因此您不能让buildUI
实例化另一个组件,这是Python,因此您实际上仍然可以monkeypatch您的整个环境,使QtGui.QLabel
指向其他对象,但如果您向类传递其他“UIBuilder”对象,则会更简单,该对象将提供示例组件,并使用QtUIBuilder
进行生产,或使用一些MockUIBuilder
进行测试。这被称为“依赖注入”。