views:

311

answers:

1

I'm using contracts for Python to specify preconditons/postconditions/invariants. I'm also using doctests for doing unit testing.

I'd like to have all of my doctest unit tests run with contracts enabled, and I'd like to run my tests using nose. Unfortunately, if I run the tests with nose, it does not execute the pre/post/invariant assertions. I put a setup function in each .py file to make sure that contract.checkmod gets called

def setup():
    import contract
    contract.checkmod(__name__)

I can confirm that this function is being executed by nose before it runs the tests, but the contracts still don't get executed.

On the other hand, if I run the doctest by calling doctest.testmod, the pre/post/inv do get called:

def _test():
    import contract
    contract.checkmod(__name__)
    import doctest
    doctest.testmod()

if __name__=='__main__':    
    _test()

Here's an example of a Python script whose test will succeed if called directly, but failed if called with nose:

import os

def setup():
    import contract
    contract.checkmod(__name__)

def delete_file(path):
    """Delete a file. File must be present.

    >>> import minimock
    >>> minimock.mock('os.remove')
    >>> minimock.mock('os.path.exists', returns=True)

    >>> delete_file('/tmp/myfile.txt')
    Called os.path.exists('/tmp/myfile.txt')
    Called os.remove('/tmp/myfile.txt')

    >>> minimock.restore()

    pre: os.path.exists(path)
    """
    os.remove(path)

if __name__ == '__main__':
    setup()
    import doctest
    doctest.testmod()

When I run the above file standalone, the tests pass:

$ python contracttest.py -v
Trying:
    import minimock
Expecting nothing
ok
Trying:
    minimock.mock('os.remove')
Expecting nothing
ok
Trying:
    minimock.mock('os.path.exists', returns=True)
Expecting nothing
ok
Trying:
    delete_file('/tmp/myfile.txt')
Expecting:
    Called os.path.exists('/tmp/myfile.txt')
    Called os.remove('/tmp/myfile.txt')
ok
Trying:
    minimock.restore()
Expecting nothing
ok
2 items had no tests:
    __main__
    __main__.setup
1 items passed all tests:
   5 tests in __main__.delete_file
5 tests in 3 items.
5 passed and 0 failed.
Test passed.

Here it is with nose:

$ nosetests --with-doctest contracttest.py
F
======================================================================
FAIL: Doctest: contracttest.delete_file
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/System/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/doctest.py", line 2131, in runTest
    raise self.failureException(self.format_failure(new.getvalue()))
AssertionError: Failed doctest test for contracttest.delete_file
  File "/Users/lorin/Desktop/contracttest.py", line 10, in delete_file

----------------------------------------------------------------------
File "/Users/lorin/Desktop/contracttest.py", line 17, in contracttest.delete_file
Failed example:
    delete_file('/tmp/myfile.txt')
Expected:
    Called os.path.exists('/tmp/myfile.txt')
    Called os.remove('/tmp/myfile.txt')
Got:
    Called os.remove('/tmp/myfile.txt')


----------------------------------------------------------------------
Ran 1 test in 0.055s
A: 

I tried your sample, it works.

When use nose, it does nothing. No error. What is your error info?

chenge
I edited above to show the error. You need to tell nose to look for doctests using the --with-doctest flag.
lorin