unittest help needed!

O

Oltmans

Hi Python gurus,

I'm quite new to Python and have a problem. Following code resides in
a file named test.py
---
import unittest


class result(unittest.TestResult):
pass



class tee(unittest.TestCase):
def test_first(self):
print 'first test'
print '-------------'
def test_second(self):
print 'second test'
print '-------------'
def test_final(self):
print 'final method'
print '-------------'

r = result()
suite = unittest.defaultTestLoader.loadTestsFromName('test.tee')

suite.run(r)

---

Following is the output when I run it
---
final method
-------------
first test
-------------
second test
-------------
final method
 
E

exarkun

Hi Python gurus,

I'm quite new to Python and have a problem. Following code resides in
a file named test.py
---
import unittest


class result(unittest.TestResult):
pass



class tee(unittest.TestCase):
def test_first(self):
print 'first test'
print '-------------'
def test_second(self):
print 'second test'
print '-------------'
def test_final(self):
print 'final method'
print '-------------'

r = result()
suite = unittest.defaultTestLoader.loadTestsFromName('test.tee')

suite.run(r)

---

Following is the output when I run it

When you run test.py, it gets to the loadTestsFromName line. There, it
imports the module named "test" in order to load tests from it. To
import
that module, it runs test.py again. By the time it finishes running the
contents of test.py there, it has run all of your tests once, since part
of test.py is "suite.run(r)". Having finished that, the import of the
"test"
module is complete and the "loadTestsFromName" call completes. Then,
the
"suite.run(r)" line runs again, and all your tests run again.

You want to protect the suite stuff in test.py like this:

if __name__ == '__main__':
...

Or you want to get rid of it entirely and use `python -m unittest
test.py`
(with a sufficiently recent version of Python), or another runner, like
Twisted Trial or one of the many others available.

Jean-Paul
 
O

Oltmans

When you run test.py, it gets to the loadTestsFromName line.  There, it
imports the module named "test" in order to load tests from it.  To
import
that module, it runs test.py again.  By the time it finishes running the
contents of test.py there, it has run all of your tests once, since part
of test.py is "suite.run(r)".  Having finished that, the import of the
"test"

Many thanks, really appreciate your insight. Very helpful. I need a
program design advice. I just want to know what's the gurus way of
doing it? I've a unittest.TestCase derived class that have around 50
test methods. Design is almost similar to following
---
import unittest

class result(unittest.TestResult):
pass

class tee(unittest.TestCase):
def test_first(self):
print 'first test'
process(123)
def test_second(self):
print 'second test'
process(564)
def test_third(self):
print 'final method'
process(127863)



if __name__=="__main__":
r = result()
suite = unittest.defaultTestLoader.loadTestsFromName('test.tee')
suite.run(r)
---

As you can see, every test method is almost same. Only difference is
that every test method is calling process() with a different value.
Also, I've around 50 test methods coded that way. I just want to know:
is there a way I can make things smaller/smarter/pythonic given the
current design? If you think any information is missing please let me
know. I will really really appreciate any insights. Many thanks in
advance.
 
P

Phlip

Oltmans said:
def test_first(self):
print 'first test'
process(123)

All test cases use the pattern "Assemble Activate Assert".

You are assembling a 123, and activating process(), but where is your assert? If
it is inside process() (if process is a test-side method), then that should be
called assert_process().
As you can see, every test method is almost same. Only difference is
that every test method is calling process() with a different value.
Also, I've around 50 test methods coded that way.

We wonder if your pattern is truly exploiting the full power of testing. If you
have ~15 different features, you should have ~50 tests (for a spread of low,
middle, and high input values, to stress the targeted production code).

But this implies your 15 different features should have as many different
interfaces - not the same interface over and over again. That suggests coupled
features.

Anyway, the short-term answer is to temporarily abandon "AAA", and roll up your
input values into a little table:

for x in [123, 327, 328, ... ]:
process(x)

(Also, you don't need the print - tests should run silent and unattended, unless
they fail.)

This refactor is the standard answer to the question "I have an unrolled loop".
You roll it back up into a table iteration.

However, you lose the test case features, such as restartability and test
isolation, that AAA give you.

Long term, you should use a literate test runner, such as (>cough<) my Morelia
project:

http://c2.com/cgi/wiki?MoreliaViridis

Down at the bottom, that shows how to create a table of inputs and outputs, and
Morelia does the unrolling for you.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top