Works great! I added an "import copy" in db.py, and added a line in my
unit test to rename "test_db" to "db" so that functions in the test
script will use the test DB.

For posterity, here is a complete working example of unit tests with
web2py, with access to the database, using test database. The wiki
article I create will explain each piece and why it's needed.

====== To run the unit tests, type this on the command line: ======
python web2py.py -S api -M -R applications/api/controllers/test.py  #
Fill in your own values for the test file and controller name
================================================

====== applications/api/controllers/test.py ======
#!/usr/bin/python
import sys
import unittest

from gluon.globals import Request  # So we can reset the request for
each test

sys.arvg = sys.argv[5:]  # web2py.py passes the whole command line to
this script

db = test_db  # Rename the test database so that functions will use it
instead of the real database
execfile("applications/api/controllers/10.py", globals())  # Brings
the controller's functions into this script's scope

class TestListActiveGames(unittest.TestCase):
    def setUp(self):
        request = Request()  # Use a clean request

    def testListActiveGames(self):
        # Set variables for the test function
        request.post_vars["game_id"] = 1
        request.post_vars["username"] = "spiffytech"

        # Call a function from the controller "10.py" and print the
dictionary it returns
        resp = list_active_games()
        print resp
        self.assertEquals(0, len(resp["games"]))

# Manually specify tests to run; the web2py environment breaks
unittest.main()
# Taken from here: 
http://agiletesting.blogspot.com/2005/01/python-unit-testing-part-1-unittest.html
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestListActiveGames))
unittest.TextTestRunner(verbosity=2).run(suite)

db(db.game.id>0).delete()  # Empty out the test database so it's fresh
for next time
======================================

====== Added to the bottom of applications/api/models/db.py ======
# Create a test database that's laid out just like the "real" database
import copy
test_db = DAL('sqlite://testing.sqlite')  # DB name and location
for tablename in db.tables:  # Copy tables!
    table_copy = [copy.copy(f) for f in db[tablename]]
    test_db.define_table(tablename, *table_copy)

===================================================


On Feb 25, 11:36 am, Thadeus Burgess <thade...@thadeusb.com> wrote:
> So the easiest way to use a testing db and your existing tables is to
> automatically recreate them.
>
> So assuming you are in the web2py environment and have access to ``db``
>
> >>> test_db = DAL('testing.sqlite')
> >>> for tablename in db.tables:
> >>>   table_copy = [copy.copy(f) for f in db[tablename]]
> >>>   test_db.define_table(tablename, *table_copy)
>
> This will create a new testing sqlite database. Then it will go
> through all tables defined in db, then copy their fields to a list,
> then it will define a new table in the sqlite with the copied fields.
>
> Now any functions that you might want to unit test might rely on your
> ``db`` object, which could be an issue depending on how you have your
> code structured.
>
> -Thadeus
>
> On Thu, Feb 25, 2010 at 8:02 AM, Tiago Almeida
>
> <tiago.b.alme...@gmail.com> wrote:
> > I concur. Thanks :)
>
> > On Thu, Feb 25, 2010 at 1:52 PM, Nicol van der Merwe <aspersie...@gmail.com>
> > wrote:
>
> >> Super awesome, thanks!
>
> >> On Thu, Feb 25, 2010 at 3:43 PM, spiffytech <spiffyt...@gmail.com> wrote:
>
> >>> I'm going to write up a nice, clear wiki article on unit testing with
> >>> the unittest module based on what I learned in this discussion. I'll
> >>> be sure to link to it here when it's done.
>
> >>> On Feb 25, 4:20 am, Nicol van der Merwe <aspersie...@gmail.com> wrote:
> >>> > Hi guys
>
> >>> > This stuff is very interesting. I would like to request, if possible,
> >>> > that
> >>> > someone makes a web2pyslice or proper AlterEgo entry on how to setup
> >>> > and run
> >>> > these kinds of tests for web2py. I am very interested in setting up
> >>> > tests
> >>> > for my application but I'm a bit lost as I've never done so before
> >>> > (plus I'm
> >>> > unfortunately just too busy to research all this and make my own
> >>> > slice).
>
> >>> > It would be very much appreciated if this can be done :)
>
> >>> > Nicolaas
>
> >>> > On Thu, Feb 25, 2010 at 5:35 AM, spiffytech <spiffyt...@gmail.com>
> >>> > wrote:
> >>> > > Thanks! Interesting article! My test cases now execute. However, I
> >>> > > have a couple new questions, including a problem accessing the db in
> >>> > > my controller.
>
> >>> > > I modified my test file as AlterEgo 213 indicates so my unit tests
> >>> > > can
> >>> > > access the controller's functions. Here is my updated test file:
>
> >>> > > ==============
> >>> > > #!/usr/bin/python
> >>> > > import sys
> >>> > > import unittest
>
> >>> > > from gluon.shell import exec_environment
> >>> > > from gluon.globals import Request, Response, Session
> >>> > > from gluon.storage import Storage
>
> >>> > > sys.arvg = sys.argv[5:]  # web2py.py passes the whole command line to
> >>> > > this script
>
> >>> > > class TestListActiveGames(unittest.TestCase):
> >>> > >    def setUp(self):
> >>> > >        self.request = Request()  # Use a clean Request
> >>> > >        self.controller = exec_environment('applications/api/
> >>> > > controllers/10.py', request=self.request)
>
> >>> > >    def testListActiveGames(self):
> >>> > >        self.request.post_vars["game_id"] = 1
> >>> > >        self.request.post_vars["username"] = "spiffytech"
> >>> > >        self.controller.list_active_games()
>
> >>> > > suite = unittest.TestSuite()
> >>> > > suite.addTest(unittest.makeSuite(TestListActiveGames))
> >>> > > unittest.TextTestRunner(verbosity=2).run(suite)
> >>> > > ==============
>
> >>> > > It is called with the command:
>
> >>> > > ==============
> >>> > > python web2py.py -S api -M -R applications/api/tests/test.py
> >>> > > ==============
>
> >>> > > The output is this:
>
> >>> > > ==============
> >>> > > web2py Enterprise Web Framework
> >>> > > Created by Massimo Di Pierro, Copyright 2007-2010
> >>> > > Version 1.75.4 (2010-02-18 20:57:56)
> >>> > > Database drivers available: pysqlite2
> >>> > > testListActiveGames (__builtin__.TestListActiveGames) ... ERROR
>
> >>> > > ======================================================================
> >>> > > ERROR: testListActiveGames (__builtin__.TestListActiveGames)
>
> >>> > > ----------------------------------------------------------------------
> >>> > > Traceback (most recent call last):
> >>> > >  File "applications/api/tests/test.py", line 19, in
> >>> > > testListActiveGames
> >>> > >    self.controller.list_active_games()
> >>> > >  File "applications/api/controllers/10.py", line 47, in
> >>> > > list_active_games
> >>> > >    games = db(((db.game.user1==username)|(db.game.user2==username)) &
> >>> > > (db.game.victory==-2)).select(db.game.user1, db.game.user2,
> >>> > > db.game.id, db.game.turn_number).as_list()
> >>> > > NameError: global name 'db' is not defined
>
> >>> > > ----------------------------------------------------------------------
> >>> > > Ran 1 test in 0.008s
>
> >>> > > FAILED (errors=1)
> >>> > > ==============
>
> >>> > > Questions:
> >>> > > 1) How can I get my controller to see the database?
> >>> > > 2) Am I simply doing something very wrong? I would expect the web2py
> >>> > > "-
> >>> > > S" option to set up the environment, complete with my controller's
> >>> > > functions, and Request/Storage/Response objects available for
> >>> > > instantiation. However, several posts on the mailing list indicate
> >>> > > that I need to run exec_enviroment() for access to my controllers.
> >>> > > Also, the Request/Storage/Response objects don't seem to exist in the
> >>> > > shell.
>
> >>> > > On Feb 24, 2:52 pm, Thadeus Burgess <thade...@thadeusb.com> wrote:
> >>> > > > Replacing the way you run test suites helps. Instead of using
> >>> > > > .main()
> >>> > > > add them manually.
>
> >>> > > > I would suggest reading the following article, as it includes
> >>> > > > methods
> >>> > > > to aggregate your test suites together.
>
> >>> > > > >http://agiletesting.blogspot.com/2005/01/python-unit-testing-part-1-u...
>
> >>> > > > import sys
> >>> > > > sys.argv = sys.argv[5:]
>
> >>> > > > import unittest
>
> >>> > > > class TestDefaultController(unittest.TestCase):
>
> >>> > > >     def testPrintStatement(self):
> >>> > > >         print "This line should print"
> >>> > > >     def testDatabaseRecordCount(self):
> >>> > > >         print "Records in database --- ",
> >>> > > > db(db.auth_user.id>0).count()
>
> >>> > > > suite = unittest.TestSuite()
> >>> > > > suite.addTest(unittest.makeSuite(TestDefaultController))
> >>> > > > unittest.TextTestRunner(verbosity=2).run(suite)
>
> >>> > > > python web2py.py -S pms -M -R
> >>> > > applications/pms/test/testDefaultController.py
> >>> > > > web2py Enterprise Web Framework
> >>> > > > Created by Massimo Di Pierro, Copyright 2007-2010
> >>> > > > Version 1.75.4 (2010-02-18 14:55:03)
> >>> > > > Database drivers available: SQLite3
> >>> > > > /home/thadeusb/web2py/applications/pms/modules/utils.py:16:
> >>> > > > DeprecationWarning: the md5 module is deprecated; use hashlib
> >>> > > > instead
> >>> > > >   import md5
> >>> > > > testDatabaseRecordCount (__builtin__.TestDefaultController) ...
> >>> > > > Records in database ---  4052
> >>> > > > ok
> >>> > > > testPrintStatement (__builtin__.TestDefaultController) ... This
> >>> > > > line
> >>> > > > should print
> >>> > > > ok
>
> >>> > > > ----------------------------------------------------------------------
> >>> > > > Ran 2 tests in 0.006s
>
> >>> > > > OK
>
> >>> > > > -Thadeus
>
> >>> > > > On Wed, Feb 24, 2010 at 12:50 PM, spiffytech <spiffyt...@gmail.com>
> >>> > > wrote:
> >>> > > > > The confusion is not with doctests, but with external unit tests
> >>> > > > > created with the 'unittest' module. Could you please post your
> >>> > > > > testControllerDefault.py so I can see what you're doing different
> >>> > > > > from
> >>> > > > > me?
>
> >>> > > > > Please allow me to elaborate on my problems running unit tests
> >>> > > > > with
> >>> > > > > web2py. Here is my (very minimal) example unit test file:
> >>> > > > > =================
> >>> > > > > #!/usr/bin/python
> >>> > > > > import unittest
>
> >>> > > > > class TestListActiveGames(unittest.TestCase):
> >>> > > > >    def testListActiveGames(self):
> >>> > > > >        print "This line should print out"
>
> >>> > > > > if __name__ == "__main__":
> >>> > > > >    unittest.main()
> >>> > > > > =================
>
> >>> > > > > If the test is actually run, the command line will show "This
> >>> > > > > line
> >>> > > > > should print out".
>
> >>> > > > > The file is stored at
> >>> > > > > <web2py_root>/applications/api/tests/test.py. My
> >>> > > > > current working directory is <web2py_root>.
> >>> > > > > I run the following command:
>
> >>> > > > > =======
> >>> > > > > python web2py.py -S api -M -R applications/api/tests/test.py
> >>> > > > > =======
>
> >>> > > > > And I get this output:
>
> >>> > > > > ================
> >>> > > > > web2py Enterprise Web Framework
> >>> > > > > Created by Massimo Di Pierro, Copyright 2007-2010
> >>> > > > > Version 1.75.4 (2010-02-18 20:57:56)
> >>> > > > > Database drivers available: pysqlite
> >>> > > > > ================
>
> >>> > > > > The output does not contain the line, "This line should print
> >>> > > > > out",
> >>> > > > > indicating the unit tests are not being run.
>
> >>> > > > > I did some debugging and found that the last two lines, which are
> >>> > > > > typical for unittest files, do not work when the file is executed
> >>> > > > > by
> >>> > > > > web2py. Rather than being equal to "__main__", which indicates
> >>> > > > > the
> >>> > > > > file is being executed from the command line, __name__ is equal
> >>> > > > > to
> >>> > > > > "__builtin__". I modified the code to work anyway:
>
> >>> > > > > ================
> >>> > > > > #!/usr/bin/python
> >>> > > > > import unittest
>
> >>> > > > > class TestListActiveGames(unittest.TestCase):
> >>> > > > >    def testListActiveGames(self):
> >>> > > > >        print "This line should print out"
>
> >>> > > > > unittest.main()
> >>> > > > > ================
>
> >>> > > > > Now, I receive this output:
>
> >>> > > > > =======
> >>> > > > > web2py Enterprise Web Framework
> >>> > > > > Created by Massimo Di Pierro, Copyright
>
> ...
>
> read more »

-- 
You received this message because you are subscribed to the Google Groups 
"web2py-users" group.
To post to this group, send email to web...@googlegroups.com.
To unsubscribe from this group, send email to 
web2py+unsubscr...@googlegroups.com.
For more options, visit this group at 
http://groups.google.com/group/web2py?hl=en.

Reply via email to