[Tutor] unit testing

Tom Plunket py-tutor@fancy.org
Sat May 31 14:06:01 2003


Magnus Lyckå wrote:

> It'll come to you. It's proably just too simple! ;)

That's what I fear.

> I guess you realize the difference between Python's "import"
> and "#include" in C++. Import always makes it's own namespace...

Sure- is there a way that I can call __import__ to look like
"from x import *" though?

> I use a script like this:
> ---------------
> import glob, os, time
> 
> start = time.time()
> tests = glob.glob('*_ut.py') # You'd change this to 'test_*.py'
> tests.sort()
> for test in tests:
>      print "Running", test
>      os.system('python ' + test)
> stop = time.time()
> 
> print "Ran %i test modules in %.3f seconds real time" % (len(tests), 
> stop-start)

Interesting.  My only fear is that, for a program with a lot of
modules, that this spits a lot of trash on the screen.

> Each of my test files contain:
> 
> if __name__ == "__main__":
>      unittest.main()

Try adding the line "print 'done!'" after that.  You'll find
that, since unittest.main() calls sys.exit(), you never hit your
print statement.  At least, that's how it is coded in my 2.2.2
install.

(like this:
:     def runTests(self):
:         if self.testRunner is None:
:             self.testRunner = TextTestRunner(verbosity=self.verbosity)
:         result = self.testRunner.run(self.test)
:         sys.exit(not result.wasSuccessful())
)

I don't recall off the top of my head what exception is thrown in
this case, but normally it's supressed by the environment (or so
it seems).

> I'm sure this can be handled differently, so that I don't have to
> call os.system, but I wrote this and it worked well enough.

And with testing, that's all it needs to do!  :)

> By doing it like this, I also know that each test module is run 
> independently, that there are no inadvertant dependencies between 
> test modules, since each module runs in a new process.

That's a good point, although I do try to make sure there are no
dependencies anyway by limiting my use of global variables to
none and trying to always create new class instances.  :)

> Note that only a fraction of the Python regression tests use unittest.

Sure- I was just inspired by the way they were loading up test
modules.

> >(although I also don't understand why I can't
> >import test.regrtest):
> 
> Neither do I. In Active Python 2.2.2 I can do:
> 
>  >>> import test.regrtest
>  >>> help(test.regrtest)
> Help on module test.regrtest in test:

Hmm...  In IDLE I can do that too.  Unfortunately:

C:\Documents and Settings\tom\My Documents>type test.py
import test.regrtest

C:\Documents and Settings\tom\My Documents>test.py
Traceback (most recent call last):
  File "C:\Documents and Settings\tom\My Documents\test.py", line
1, in ?
    import test.regrtest
  File "C:\Documents and Settings\tom\My Documents\test.py", line
1, in ?
    import test.regrtest
ImportError: No module named regrtest

> >Why isn't my code pulling my tests into my local namespace?
> 
> Because you are explicitly pulling it into a variable
> called 'module' instead? You tell me, you wrote it! ;)

Heh- ok, then as above, how do I pull into the local namespace
using __import__ ?

> I would *not* try to pull all my modules into the same
> namespace.

I will probably have an epiphany one day that this is not what I
want, but for the sake of learning...  ;)

> If each test has it's own namespace, there will be no name 
> collisions as long as you don't have collisions in a single file. 

Hmm- there's something interesting.  Maybe I could hack unittest
so that it takes a list of modules to run.  ...or maybe that's
what that 'argv' parameter is for.  Hmm, maybe I can do it just
by passing my 'tests' list in as argv.

> I can understand your frustration. Sometimes it's easier to
> be a complete newbie than to be used to something working in
> a particular way, and then come to a place where things work
> slightly differently. As Yoda said: "You have to unlearn what
> you have learnt." :)

Yes indeed- I actually had similar frustrations when moving
between C++ compilers, even.  The way to do things optimally
often depended entirely on the compiler.  :(

Thanks for your help-
-tom!