setUp and tearDown per class not per test fixture

Asked by Tim Chan

Is there a way to call setUp and tearDown once per class, instead of per test fixture.
I'm testing a web app. My setUp includes the login process and my tearDown is my logout process. It would be more efficient if I log in once, execute all my tests then log out at the end.

Question information

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

--- One .sikuli = one (implicit) test class
--- One setUp, one tearDown

So you may pack as many test-def()'s in there, as you like

If you want to be even more flexible, just use Python/Jythons unittest module.

Revision history for this message
Jörg (jmkoch) said :
#2

Same problem here, setUp and tearDown is executed for every test def.

Would be nice if this works per .sikuli

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

the following "hack" should help:

def setup(self):
   try:
      self.already_done += 1
      if self.already_done > 0: return
   except:
      self.already_done = 0
      return
   # your other code

def teardown(self)
   if self.already_done > 0: return
   # your other code

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

sorry just realized, my comment #1 is absolute nonsense.

Per definition, (same goes for Python unittest):

for each test function in a test class (equivalent to a .sikuli) setup/teardown is processed once.

Revision history for this message
Jörg (jmkoch) said :
#5

I tried the "hack":
- When I click "Run" on the "Unit Test" sidebar, the main window disappears and the small test window shows up.
- Yet, the tests do not start. I think I'm getting an exception here but I cannot return to the Sikuli main window.
- I have to quit Sikuli and start it again

Thx for any help!

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

This might help to recover from the syntax error https://bugs.launchpad.net/sikuli/+bug/778672/comments/3

In general it is always a good idea, to "run" your test script with the normal Run button, after having made changes and saved it again: nothing should happen though, but syntax errors, that would prevent the script to run in the unit test window are reported.

the hack:
I admit, that I have just written it down in this post, without having tested it in the IDE (I was in a hurry). I will test it now and report any necessary comments.

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

with teardown a colon is missing:

def setup(self):
   try:
      self.already_done += 1
      if self.already_done > 0: return
   except:
      self.already_done = 0
      return
   # your other code

def teardown(self):
   if self.already_done > 0: return
   # your other code

Revision history for this message
Jörg (jmkoch) said :
#8

The initialization of self.already_done = 0 is not kept, the code always jumps to the except clause.

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

ok, I have checked it: the solution to use the test class (self) as global storage does not work for more than one test. this is only a solution to give information from setUp to testXXX to tearDown.

And another thing (sorry): setUp and tearDown are camel cased!

So this is a solution that at least works, when running the test from command line with option -t.
In the IDE it only works once, since the IDE does not reset it's environment on rerun, so setUp and tearDown are not processed on rerun. There has to be some other logic added to realize, that a rerun is started.

CAUTION: Sikuli runs the tests in reverse order as you might have already noticed. This does not matter in the standard, but might be relevant in your case.

This is the script that works as expected (using Sikuli's Settings class as global storage)

def setUp(self):
 print "setup entry"
 try:
  Settings.already_done += 1
  if Settings.already_done > 0: return
 except:
  Settings.already_done = 0
 print "setup processing"
 # your other code

def testA(self):
 print "testA"
 Settings.already_done += 1
 return True

def testB(self):
 print "testB"
 Settings.already_done += 1
 return True

def testC(self):
 print "testC"
 Settings.already_done += 1
 return True

def testD(self):
 print "testD"
 Settings.already_done += 1
 return True

def tearDown(self):
 print "teardown entry"
 if Settings.already_done > 1: return
 print "teardown processing"
 # your other code

Revision history for this message
Jörg (jmkoch) said :
#10

Thx, I now got the following solution, working multiple times in the IDE, by setting already_done to None at tearDown:

def setUp(self):
 print "setup entry"
 try:
  Settings.already_done += 1
  if Settings.already_done > 0: return
 except:
  Settings.already_done = 0
  print "setup processing"
  # your other code

def tearDown(self):
 print "teardown entry"
 if Settings.already_done >= "number of tests -1":
  print "teardown processing"
  Settings.already_done = None
  # your other code

def testA(self):
 print "testA"
 return True

def testB(self):
 print "testB"
 return True

def testC(self):
 print "testC"
 return True

Revision history for this message
Jörg (jmkoch) said :
#11

"number of tests -1" in this example is of course 2.

Is there a way to get the number of tests or functions?

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

Yes I alredy thought about that solution. It is indead possible. I will come back with that.

But sometimes one can really be blind for the nice and easy solutions:

just move your setUp code to an extra testSetUp at the end (processed first) and the tearDown code to an extra testTearDown at the beginning (processed last) and leave out setUp and tearDown (not needed in this case)
not tested yet, but should work.

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

And here how to get the number of tests:

import inspect
numberOfTests = len([e for e in inspect.getmembers(self) if e[0].startswith('test')])

Revision history for this message
Jörg (jmkoch) said :
#14

The suggestion with testSetUp and testTearDown does not work. The execution of the tests does not seem to be exactly bottom up?!

The numberOfTests read correctly!

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

Ok, nice try ;-)

So this should be the final version that runs correctly in the IDE AND from command line:

(the print statements are for testing purposes and have to be replaced by your appropriate code)

def setUp(self):
 try:
  int(Settings.already_done) # this should fail at start
  if Settings.already_done > 0: return
 except:
  Settings.already_done = 0
  import inspect
  Settings.numberOfTests = len([e for e in inspect.getmembers(self) if e[0].startswith('test')])
 print "the other setUp code --", Settings.numberOfTests

def tearDown(self):
 if Settings.already_done >= Settings.numberOfTests: Settings.already_done = None; return
 elif Settings.already_done > 1: return
 print "the other tearDown code"

def testA(self):
 Settings.already_done += 1 # first line in every test
 print "the other testA code --", Settings.already_done
 return True

def testB(self):
 Settings.already_done += 1 # first line in every test
 print "the other testB code --", Settings.already_done
 return True

# more tests might follow

Can you help with this problem?

Provide an answer of your own, or ask Tim Chan for more information if necessary.

To post a message you must log in.