Re: A new syntax for writing tests

Discussion in 'Python' started by Jean-Michel Pichavant, Aug 5, 2010.

  1. Jonathan Fine wrote:
    > Hi
    >
    > I just discovered today a new syntax for 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."

    source
    http://docs.python.org/library/unittest.html

    As you can see, a much more featured test framework already exists.

    There's nothing wrong in a new test framework, but it has to be better
    than the existing one in some situations.

    JM
     
    Jean-Michel Pichavant, Aug 5, 2010
    #1
    1. Advertising

  2. Jean-Michel Pichavant

    jfine Guest

    On 5 Aug, 10:17, Jean-Michel Pichavant <> 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 a new
    *syntax* for writing tests. Tests written in the new syntax can be
    run in the unittest (or any other) framework.

    --
    Jonathan
     
    jfine, Aug 5, 2010
    #2
    1. Advertising

  3. jfine wrote:
    > On 5 Aug, 10:17, Jean-Michel Pichavant <> 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 a new
    > *syntax* for writing tests. Tests written in the new syntax can 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.


    JM

    PS : I think your usage of 'syntax' is inapropriate.
     
    Jean-Michel Pichavant, Aug 5, 2010
    #3
  4. Jean-Michel Pichavant

    jfine Guest

    On 5 Aug, 14:52, Jean-Michel Pichavant <> wrote:
    > jfine wrote:
    > > On 5 Aug, 10:17, Jean-Michel Pichavant <> 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
     
    jfine, Aug 5, 2010
    #4
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Phillip Lord

    JUnit, writing todo tests...

    Phillip Lord, Feb 9, 2004, in forum: Java
    Replies:
    4
    Views:
    845
    Scott Ellsworth
    Feb 12, 2004
  2. Replies:
    8
    Views:
    906
  3. Steven D'Aprano

    Writing tests for the Python bug tracker

    Steven D'Aprano, Mar 20, 2010, in forum: Python
    Replies:
    5
    Views:
    282
    Mark Dickinson
    Mar 20, 2010
  4. dayo
    Replies:
    11
    Views:
    357
    Ilya Zakharevich
    Dec 16, 2005
  5. Replies:
    2
    Views:
    484
    Thomas 'PointedEars' Lahn
    Mar 11, 2008
Loading...

Share This Page