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.