Can sikuli take a screenshot on failure / error? --- rc3: currently no

Asked by The Happy Rock

It would be very helpful to see what the screen was like when a test failed, especially when running a suite of tests.

Question information

Language:
English Edit question
Status:
Solved
For:
SikuliX Edit question
Assignee:
No assignee Edit question
Solved by:
RaiMan
Solved:
Last query:
Last reply:
Revision history for this message
Best RaiMan (raimund-hocke) said :
#1

I do not think, that this will ever be a feature.

You have to implement it on your own.

If you do, I recommend to use Python or Java unit test directly and not the IDE unit test feature, which currently has many bugs and restrictions (import not possible).

Revision history for this message
The Happy Rock (thehappyrock) said :
#2

Thanks for the quick answer.

I was able to find a reasonable workaround.

Using the information from this question : https://answers.launchpad.net/sikuli/+question/164161

I added the following code to my tearDown methods that takes a screenshot if there was an error :

from java.awt import *
from java.io import File
from javax.imageio import ImageIO

if hasattr(test, 'failureException'):
     robot = Robot()
     theImage = robot.createScreenCapture(Rectangle(Toolkit.getDefaultToolkit().getScreenSize()))
     ImageIO.write(theImage, "png", File(r"C:\myPic.png"))

Note: test is an instance of TestCase

The solution isn't perfect, since error in setUp won't get a screenshot and you have to put code into every test rather than having it automatically fire.

Still it is nice that I have java and python at my disposal to create a workaround

Revision history for this message
The Happy Rock (thehappyrock) said :
#3

Thanks RaiMan, that solved my question.

Revision history for this message
RaiMan (raimund-hocke) said :
#4

Motivated by your idea, I found a neat solution, that might extend the support for unit testing through Sikuli "dramatically".

This is a generalized solution, that allows to make and store a screenshot, in case a test function fails, exactly in the same moment.

You do not have to touch your TestCase's code.

Based on the documentation at:
http://docs.python.org/library/unittest.html

--- a basic all in one template (e.g. mainTest.sikuli):

import unittest

class TestSik(unittest.TestCase):
    def setUp(self):
        print "\n*** in setUp"
    def test1(self):
        print "*** in Test1"
        assert False
    def test2(self):
        print "*** in Test2"
        assert True
    def tearDown(self):
        print "*** in tearDown"

class myTestResult(unittest.TestResult):
    def addFailure(self, test, err):
        print "\n*** from addFailure",test, err
        unittest.TestResult.addFailure(self,test,err)

tr = myTestResult()

suite = unittest.TestLoader().loadTestsFromTestCase(TestSik)
suite.run(tr)

# did not find out yet, how to use TextTestRunner
# to get some readable output from myTestResult instance
print "*** Test summary ----------------"
print "Tests run:", tr.testsRun
if tr.wasSuccessful():
    print "no Failures"
    exit(0)
print "Failures:", len(tr.failures)
print "--------------"
for e in tr.failures:
    print "*** FAIL:", e[0]
    x = e[1].split("\n")
    x1 = " ".join(x[1].split(",")[1:3])
    print "%s ( %s )"%(x1, x[2].strip())
    print "--------------"
exit(1)

The trick is to subclass TestResult and overwrite the respective method (in this case addFailure, which is called when a test fails).
Here we can do, whatever we want and finally go back to the original method, to let TestResult do its job.

This might be further packed in a utility class/module, that can be used all over the place.