Index: openacs-4/packages/acs-core-docs/www/xml/developers-guide/tutorial-debug.xml =================================================================== RCS file: /usr/local/cvsroot/openacs-4/packages/acs-core-docs/www/xml/developers-guide/tutorial-debug.xml,v diff -u -N -r1.6 -r1.7 --- openacs-4/packages/acs-core-docs/www/xml/developers-guide/tutorial-debug.xml 2 Feb 2004 08:32:36 -0000 1.6 +++ openacs-4/packages/acs-core-docs/www/xml/developers-guide/tutorial-debug.xml 4 Feb 2004 16:47:34 -0000 1.7 @@ -1,15 +1,11 @@ - %myvars; ]> Debugging and Automated Testing - - This section is a work in progress. - - by Joel Aufrecht @@ -27,20 +23,19 @@ PostgreSQL You can work directly with the database to do debugging steps like looking directly at tables and testing stored - procedures. Start emacs. Type + procedures. Start emacs. Type M-x sql-postgres. Press enter for - server name and use openacs-dev for + server name and use service0 for database name. You can use C-(up arrow) and C-(down arrow) - for command history. + for command history. Hint: "Parse error near *" usually means that an xql file wasn't recognized, because the tcl file is choking on the *SQL* placeholder that it falls back on. Watching the server log - NOTE: explain how to add tcl to directly write your own - log output + To set up real-time monitoring of the AOLserver error log, type less /var/lib/aolserver/service0/log/openacs-dev-error.log @@ -50,7 +45,7 @@ ? searches backward / searches forward. - + Manual testing @@ -74,6 +69,21 @@ The text added in the form should be visible on the index page. + + API-001 + Invoke mfp::note::create with a specific word as the title. + Proc should return an object id. + + + API-002 + Given an object id from API-001, invoke mfp::note::get. + Proc should return the specific word in the title. + + + API-003 + Given the object id from API-001, invoke mfp::note::delete. + Proc should return 0 for success. + Other things to test: try to delete someone else's note. Try to delete your own note. Edit your own note. @@ -84,129 +94,64 @@ Write automated tests - by Simon Carstensen + by Simon Carstensen and Joel Aufrecht - - Automated tests -It seems to me that a lot of -people have been asking for some guidelines on how to write automated -tests. I've done several tests by now and have found the process to be -extremely easy and useful. It's a joy to work with automated testing -once you get the hang of it. - - I just wrote a test script for the acs-service-contract package and -thought I'd might as well post a step-by-step run-through, since some -people have been asking for this. Here goes. - - - - Create the directory that will contain the test - script(s): - -$ cd /web/simon/packages/acs-service-contract/tcl -$ mkdir test - - - - Create the .tcl library that holds the test - procs: - -$ cd test -$ emacs acs-service-contract-procs.tcl - - - - Write the tests. This is obviously the big step - :) - -The script should first call ad_library like any normal -procs.tcl file: - -ad_library { + Automated tests + It seems to me that a lot of people have been asking for some guidelines on how to write automated tests. I've done several tests by now and have found the process to be extremely easy and useful. It's a joy to work with automated testing once you get the hang of it. + Create the directory that will contain the test + script and edit the script file. The directory location and file name are standards which are recognized by the automated testing package: + [service0 www]$ mkdir /var/lib/aolserver/service0/packages/myfirstpackage/tcl/test +[service0 www]$ cd /var/lib/aolserver/service0/packages/myfirstpackage/tcl/test +[service0 test]$ emacs myfirstpackages-procs.tcl + Write the tests. This is obviously the big step :) The script should first call ad_library like any normal -procs.tcl file: + ad_library { ... } To create a test case you call aa_register_case test_case_name.. Once you've created the test case you start writing the needed logic. -Let's say you just wrote an API for adding and deleting notes in the +We'll use the tutorial package, "myfirstpackage," as an example. +Let's say you just wrote an API for adding and deleting notes in the notes packages and wanted to test that. You'd probably want to write a test that first creates a note, then verifies that it was inserted, then perhaps deletes it again, and finally verifies that it is -gone. +gone. + + Naturally this means you'll be adding a lot of bogus data to the database, which you're not really interested in having there. To avoid this I usually do two things. I always put all my test code inside a call to aa_run_with_teardown which basically means that all the inserts, deletes, and updates will be rolled back once the test has been executed. A very useful feature. Instead of inserting bogus data -like: set name "Simon", I tend to generate a random script in order avoid inserting a value that's already in the database: +like: set name "Simon", I tend to generate a random script in order avoid inserting a value that's already in the database: set name [ad_generate_random_string] Here's how the test case looks so far: -aa_register_case acs_sc_impl_new_from_spec { - - aa_run_with_teardown \ +aa_register_case mfp_basic_test { + My test +} { + aa_run_with_teardown \ -rollback \ - -testcode { - ... logic ... + -test_code { + } } - -Now let's look at the actual test code. That's the code that -goes inside -testcode {}. -In my case I had added a new column to acs_sc_impls (pretty_name), -which meant that I had to change the datamodel and the Tcl API to -support this new change. To make sure I didn't screw up, I wrote a test -that created a new service contract, then a new implementation of that -contract, and called acs_sc::impl::get to check that the data in the -new column had been added correctly and then finally verified that the -pretty_name was actually what I had tried to insert. It looked -something like this: -set spec { - name "foo_contract" - description "Blah blah" - ... -} - -# Create service contract -acs_sc::contract::new_from_spec -spec $spec - -set spec { - name "foo_impl" - description "Blah blah blah" - pretty_name "Foo Implementation" - ... -} - -# Create implementation -set impl_id [acs_sc::impl::new_from_spec -spec $spec] - -# Get the values of the implementation we just created -acs_sc::impl::get -impl_id $impl_id -array impl - -#Verify that the pretty_name column has the correct value -aa_equals "did column pretty_name get set correctly?" $impl(pretty_name) "Foo Implementation" - -Now you might not know how acs-service-contract works, but that -doesn't matter. I'm basically inserting data into the database, then -querying for the database to check that it got inserted and then -finally, using aa_equals, I compare the result with what I inserted to -verify that everything is correct. - -There are number of other useful procs for determening whether a test case was successful or not, namely: - - aa_true "is this true?" [expr ![empty_string $foo]] -aa_false "is this true?" [empty_string $foo] - There a number of other useful procs and I will encourage you to -look at the few packages for which tests have already been implemented. -That is perhaps the best documentation we have so far. See also . - - - +Now let's look at the actual test code. That's the code that +goes inside -test_code {}. We want to implement test case API-001, "Given an object id from API-001, invoke mfp::note::get. Proc should return the specific word in the title." + + set name [ad_generate_random_string] + set new_id [mfp::note::add -title $name] + aa_true "Note add succeeded" [exists_and_not_null new_id] + To test our simple case, we must load the test file into the system (just as with the /tcl file in the basic tutorial, since the file didn't exist when the system started, the system doesn't know about it.) To make this file take effect, go to the APM and choose "Reload changed" for "MyFirstPackage". Since we'll be changing it frequently, select "watch this file" on the next page. This will cause the system to check this file every time any page is requested, which is bad for production systems but convenient for developing. + Once the file is loaded, go to ACS Automated Testing and click on myfirstpackage. You should see your test case. Run it and examine the results. + Now we can add the rest of the API tests. The complete test looks like: + example missing + See also . -