Shamil Salakhetdinov
shamil at smsconsulting.spb.ru
Tue Apr 12 13:02:26 CDT 2011
Hi Jim -- <<< As result, I would develop four separate basic unit tests for that object: 1. Adding a record. 2. Deleting a record. 3. Reading a record. 4. Updating a record. >>> That would be called "integration tests" wouldn't they? That above is a bit "provocative" question I must admit to "fire" new here (?) Unit testing vs. Integration testing vs. Regression testing vs. ... testing Great Debate :) Thank you. -- Shamil -----Original Message----- From: accessd-bounces at databaseadvisors.com [mailto:accessd-bounces at databaseadvisors.com] On Behalf Of Jim Dettman Sent: 12 ?????? 2011 ?. 18:09 To: 'Access Developers discussion and problem solving' Subject: Re: [AccessD] AccessD Digest, Vol 98, Issue 7 John, If your doing any type of n-tier design, unit testing is a must and you write the tests as you develop the objects. As to your point about bugs and lines of code, unit tests are very simple and limited by nature. You only test one very specific thing with each. It's not one all encompassing test against your entire app, but rather a series of test (possibly thousands). For example, I develop a customer class, which handles CRUD operations for customers. As result, I would develop four separate basic unit tests for that object: 1. Adding a record. 2. Deleting a record. 3. Reading a record. 4. Updating a record. Then I would develop a unit test for each of the business rules, say on credit limit, can't delete a customer with open items, etc. So just for the customer object alone, I might have dozens of unit tests. Jim. -----Original Message----- From: accessd-bounces at databaseadvisors.com [mailto:accessd-bounces at databaseadvisors.com] On Behalf Of jwcolby Sent: Tuesday, April 12, 2011 9:03 AM To: Access Developers discussion and problem solving Subject: Re: [AccessD] AccessD Digest, Vol 98, Issue 7 I guess I just don't "get it". OTOH there are a lot of things I don't get. When I write a class, I look at the functions that class needs to perform it's job. If it needs a function that is used elsewhere (in Access) I go to a lib to execute that function. To a smaller extent I do the same in C# (static class methods). But in general the class functions are only used in the class. A function can be made to accept args and return a value and never modify anything external to itself. It would make programming some functionality much more complicated however. Let's take an example. I have records in SQL server where the record itself represents an object. A "supervisor" represents a database which needs a specific process applied (address validation). Due to limitations of the third party address validation program, the sets of tens of millions of addresses have to be broken down into 2 million record "chunks". The process table is child to the supervisor and each process record represents a chunk of up to 2 million records. Address validation of a table of addresses is an extremely complex task requiring dozens of steps. The Supervisor (parent) and process (child) tables contain flags to store state, "Process X has completed". It takes an entire SQL statement to write that flag back to the appropriate table (parent or child) / field. So I have a "flag class" where I initialize the class with the PKID of the record that contains this data (flag), the field name, and the table name. Now the flag class can accept a data and write that data to its specific table / record / field. So (to get back to the subject at hand) there is a process that creates a temporary database and a table to hold the tens of millions of records needing processing. The process builds that. No flag is used, we just ask SQL server whether the objects exist and create them if not. When we *fill* that table, a piece of SQL code executed in a function. That function takes database / src view information (which it does not modify) and returns a boolean true (SQL Server says it did the operation) or false (SQL Server threw an error). However the function also logs to NLog (modifies information outside of the function) with logging type of stuff such as the database name, table, number of records affected etc. *IF* the table filled, the function also directly calls the class property to set the flag (remember the flag class?) saying that it successfully filled the table in the temp database. The pro[erty actually calls the flag class and the flag class writes the data back to SQL server right then and there. The function's reason to exist is to fill a table in a temp database with data from a view in a "live" database. The function itself does not modify the parameters passed in. It returns a true / false which makes the control logic a simple if (the table filled) then else. However it also writes to the NLog the results for status debug and it writes the flag saying that it succeeded, which is immediately written back to SQL Server. There are threads in other processes polling SQL Server every N seconds asking whether there are any processes where flag XYZ has been set, IOW it is ready to move to the next stage of processing. Could I break this down into umpteen other functions that (in the end) every one only does one thing? Of course, but I ain't gonna! I like that the function logs its state in NLog and that the function logs its state in the property and I like that the property immediately writes the information back to SQL Server. I went to a great deal of effort to get all of this stuff working this way. I want a system where every step of the process immediately logs its completion and if I stop the big picture for any reason (power loss or simply shutting down the server) I can pick right up where I left off. Each such flag is written to (initialized) from the code that loads the class instance from SQL Server and then modified in the function that actually performs that step. These process step functions are only used in one place, precisely and only in the class that performs that step. They will never be called from anywhere else (in fact they are private to the class) because no other code anywhere in the world performs that step of address validation processing. As for testing... an interesting read. http://en.wikipedia.org/wiki/Unit_testing particularly "Unit testing limitations". I am not here to get in a peeing match about whether or not... But where is the unit test of the unit test code... This article claims that the unit test requires 2-3 lines of code for every line tested, and we all know that there is (statistically) 1 bug in every 20 lines of code... Since unit testing code is code, and since it introduces 2-3 lines of test code for every line tested and since there are going to be bugs in the unit test code, then we need unit test code for the unit test code for the unit test code for the unit test code for... Kind of like looking in a mirror at a reflection in a mirror behind you. Sounds like the stuff sci-fi novels are made of. ;) At any rate, as a sole proprietor I have to pick a tool which can implement the systems that I design. I am not sitting at a desk collecting a paycheck regardless of what I produce. I do not have a test department, I am the test department. I am actually fascinated with the unit testing concept but I barely have the time to write the code itself, never mind code to test the code which tests the code... Whats a guy to do? John W. Colby www.ColbyConsulting.com On 4/11/2011 4:09 PM, Kenneth Ismert wrote: > John, > > I understand the reasoning and all however... because the code is no longer >> contained within the object that needs it, you now open yourself up >> to the >> old "I need to modify this method... oops... that change breaks >> something else that uses the code". ...