A new syntax for writing tests
jfine
jonathan.fine1 at googlemail.com
Thu Aug 5 11:06:03 EDT 2010
On 5 Aug, 14:52, Jean-Michel Pichavant <jeanmic... at sequans.com> wrote:
> jfine wrote:
> > On 5 Aug, 10:17, Jean-Michel Pichavant <jeanmic... at sequans.com> wrote:
>
> >> Jonathan Fine wrote:
>
> >>> Hi
>
> >>> I just discovered today anewsyntaxfor writing tests. The basic
> >>> idea is to write a function that contains some statements, and run it
> >>> via a decorator. I wonder if anyone had seen this pattern before, and
> >>> how you feel about it. For myself, I quite like it.
>
> >>> Let's suppose we want to test this trivial (of course) class.
> >>> class Adder(object):
>
> >>> def __init__(self):
> >>> self.value = 0
>
> >>> def plus(self, delta):
> >>> self.value += delta
>
> >>> The test the class you need a runner. In this case it is quite simple.
>
> >>> def runner(script, expect):
> >>> '''Create an adder, run script, expect value.'''
>
> >>> adder = Adder()
> >>> script(adder)
> >>> return adder.value
>
> >>> We can now create (and run if we wish) a test. To do this we write
>
> >>> @testit(runner, 4)
> >>> def whatever(a):
> >>> '''Two plus two is four.'''
>
> >>> a.plus(2)
> >>> a.plus(2)
>
> >>> Depending on the exact value of the testit decorator (which in the end
> >>> is up to you) we can store the test, or execute it immediately, or do
> >>> something else.
>
> >>> The simplest implementation prints:
> >>> OK: Two plus two is four.
> >>> for this passing test, and
> >>> Fail: Two plus four is five.
> >>> expect 5
> >>> actual 6
> >>> for a test that fails.
>
> >>> Here is the testit decorator used to produce the above output:
>
> >>> def testit(runner, expect):
> >>> '''Test statements decorator.'''
>
> >>> def next(script):
> >>> actual = runner(script, expect)
> >>> if actual == expect:
> >>> print 'OK:', script.__doc__
> >>> else:
> >>> print 'Fail:', script.__doc__
> >>> print ' expect', expect
> >>> print ' actual', actual
>
> >>> return next
>
> >>> You can pick this code, for at least the next 30 days, at
> >>> http://dpaste.com/hold/225056/
>
> >>> For me the key benefit is that writing the test is really easy.
> >>> Here's a test I wrote earlier today.
>
> >>> @testit(runner, '''<a att="value"><b/></a>''')
> >>> def whatever(tb):
> >>> tb.start('a', {'att': 'value'})
> >>> tb.start('b')
> >>> tb.end('b')
> >>> tb.end('a')
>
> >>> If the test has a set-up and tear-down, this can be handled in the
> >>> runner, as can the test script raising an expected or unexpected
> >>> exception.
>
> >> Hi,
>
> >> "The unittest module provides a rich set of tools for constructing and
> >> running tests. This section demonstrates that a small subset of the
> >> tools suffice to meet the needs of most users."
>
> >> sourcehttp://docs.python.org/library/unittest.html
>
> >> As you can see, a much more featured test framework already exists.
>
> >> There's nothing wrong in anewtest framework, but it has to be better
> >> than the existing one in some situations.
>
> > Chalk and cheese.
>
> > My concern is to make tests easy to write, and that is something that
> > unittest is, in my view, not good at. It is, as you say, a *test
> > framework*.
>
> > I've not written a test framework. I've found what seems to be anew
> > *syntax* for writing tests. Tests written in thenewsyntaxcan be
> > run in the unittest (or any other) framework.
>
> > --
> > Jonathan
>
> Well, I never used unittest, but the given example in the doc is pretty
> much simple.
> I'm still scratching my head.
I think you'd understand better if you used unittest. For example,
try coding my test (with say 10 distinct tests of a class more
complicated than Adder) using unittest. I think you'll see the point
when you get to number 5.
Here, for reference, is my complete code for one test. See how it
scales.
http://dpaste.com/hold/225056/ (available for at least 30
days).
--
Jonathan
More information about the Python-list
mailing list