410 likes | 504 Views
COMS W3156: Software Engineering, Fall 2001. Lecture #14: Implementation II, LDAP Janak J Parekh janak@cs.columbia.edu. Administrativia. LDAP configured HW2 due now Design due in one week Requirements update pending (v1.2) LDAP renaming Missing some boolean operators Something else?
E N D
COMS W3156:Software Engineering, Fall 2001 Lecture #14: Implementation II, LDAP Janak J Parekh janak@cs.columbia.edu
Administrativia • LDAP configured • HW2 due now • Design due in one week • Requirements update pending (v1.2) • LDAP renaming • Missing some boolean operators • Something else? • Webboard… • You are supposed to do the homework
Next class • I’m debating
Today’s class • Implementation, continued (testing) • LDAP
From last class • Conclusion: we need a compromise – highlight faults, while accepting that not all faults will be detected • Black-box test cases first (specifications) • Then, develop additional glass-box techniques (code)
Black-box module testing • Goal: devise small number of test cases that cover most of the possibilities • Every test case must be chosen to detect a previously undetected fault: don’t repeat • Equivalence testing and boundary value analysis
Equivalence class testing • Break down cases into equivalence classes • Example: database with max 16,000 records • If it works for 251, it’ll probably work for 12,000 • Define classes that need to be tested • Less than 1 record • From 1 to 16,000 records • More than 16,000 records
Boundary testing • Take the equivalence classes to the next level • 0 records • 1 record • 2 records • 723 records • 16,382 records • 16,383 records • 16,384 records
Boundary testing (II) • Test both sides of the classes • While the example referred to input specifications, can also boundary-test output cases • Example: payroll • Test deductions between, and including, min and max deduction values, as well as beyond them • Devise test cases to get these results
Boundary testing (III) • In general, for a range {R1, R2}, 5 test cases: • Less than R1 • Equal to R1 • Greater than R1, less than R2 • Equal to R2 • Greater than R2 • Need to start thinking this way
Functional testing • Test on functionalities of module • Step 1: determine functions of module • Step 2: Devise test data for each low-level function • Step 3: Determine higher-level functions • (picture) • This is hybrid black-box and glass-box
Functional testing (II) • In practice, need to do functional analysis, since it’s not always so simple • Often, cross-module functionality • Object-oriented doesn’t help • Difficult to resolve at times, but general principle remains sound
Glass-box testing • Look at the source code, and design test cases from there • Statement coverage • Path coverage • Branch coverage
Statement coverage • Run a series of test cases in which every statement is executed at least once. • Use a CASE tool to keep track of how many times each statement has been executed • Rational PureCoverage, which we do have, but we’re probably not going to use it • Problem: no guarantee all outcomes of branches are tested (i.e. if clauses)
Branch coverage • Run a series of tests to ensure all branches are tested at least once • Tools such as Generic Coverage Tool (gct) • Statement/branch coverage are structural tests
Path coverage • Test all paths • Challenge: reduce number of paths to be examined while still uncovering as many faults as possible • Restrict test cases to linear code sequences: identify set of points from which control may jump, and devise code sequences that begin at control flow and end at another control flow
All-definition-use-path • Define each occurrence of a variable as a definition of the variable (int i=1) or use of the variable (y=i+5) • Identify all paths between definition and use • Set up a test case for each path • Still theoretically 2d paths (d = #branches) • Can be shown that in real programs this is not reached
Dead code • Sometimes programmers will have an “infeasible path” that cannot be reached given any input • Statement coverage detects this
Complexity metrics • Intuition suggests more complex code implies more bug-prone code • Various metrics to determine complexity • LOC • McCabe’s measure of cyclomatic complexity • # branches in the module • Found to be reasonably accurate • Halstead utilizes a linear combination of several metrics (operators and operands) • Problem: both Halstead and McCabe practically are linear with LOC
Code walkthroughs/inspections • Works very, very well* • Explaining your own code finds many faults • Suggest you try it in a group environment • Much cheaper than execution-based testing • Takes less time • Faults are detected earlier
Comparing testing mechanisms • Brief conclusion: all are valid, but some work a bit better than others • In some studies, it’s been shown that code reading was most effective at detecting “interface faults”, while black-box testing was most effective at finding “control faults” • Conclusion: code walkthroughts/inspections work
Cleanroom • Combine a number of different techniques, including incremental lifecycle • Critical aspect: cannot compile a module until it passes inspection • Has been successful for both small and large programs • Metric: testing faults from time of compilation
Challenges of testing objects • Can’t execution-test a class, only objects • Information hiding and simple methods complicate things: need to call both setter and getter methods to test variable changes • Need to test inherited methods! • Context may have changed: methods it may call may have been overridden
Miscellany • Management: how much time and money to test? • Cost-benefit analysis • Reliability analysis: statistical determination of faults remaining • When to rewrite? • Predetermine “maximum number of faults” • Challenges • When, how to reuse code
LDAP • Lightweight Directory Access Protocol • Essentially a hierarchical (treelike) database • Attributes: Attribute-value pair • Objects: collection of Attributes (record) • Records are uniquely identified using the DN, or distinguished name • Not XML, but you don’t need to talk the language: JNDI does the work
Distinguished name • Unique name assigned to everything in the database • Implicit hierarchy: “root” is the right part • Comma (,) is delineator • Utterly flexible • “cn=Janak,ou=PSL,ou=CS,o=Columbia” • “cn=Janak,dc=psl,dc=cs,dc=columbia,dc=edu”
Our LDAP database • Designated as “o=softe” – it’s the root of the tree • Three nodes (each have the root affixed): • ou=services • ou=actors • ou=states • Each item under this must have its own DN
Entries in LDAP • Every entry will have its own unique DN: the “identifier” will usually be a CN (Common Name) component of the DN • “cn=A1,ou=services,dc=softe,dc=cs,dc=columbia,dc=edu” • “cn=johndoe,ou=actors,dc=softe,dc=cs,dc=columbia,dc=edu”
Schema • Each entry can be one of any (millions) of types • We’ve explicitly created three for you • Service • Actor • ActorState • Names changed from requirements; will fix
Service • Service reference ID: CN tag in DN: use your group ID • Required: • ServerIP (string) • ServerPort (int) • ServerType (string): A or S • Optional • WorldName • ServerExtensions
Actor • Actor “name”/login id: CN tag in DN • Required: • HP: int • XP: int • Gold: int • Password: String • We’ll give you crypting code • Optional: • ImageURL
ActorState • CN in DN: unique identifier • Concatenate Actor, World, and Service • ac=actorname+wn=worldname+sv=servicename • Required • LocationX: int • LocationY: int • Status: int • WorldInstance: int
JNDI • Straightforward API, built into JDK 1.3 and higher • Can do more than LDAP: DNS, etc. • For LDAP, uses concept of directory context in which the operation will be done • ldap://softe.cs.columbia.edu:389/o=softe • Once set, go ahead and do operation(s) • Recitation!
JNDI Lookups • getAttributes() method searches by (unique) DN • similar to lookup() but more powerful • Returns Attributes object: collection of attribute-value pairs; you can “get” and “put”; like a Hashtable
JNDI Searches • search() searches within a DN for all entries that match the Attributes set you provide • Returns NamingEnumeration (subinterface of Enumeration) • Each entry in the Enumeration is a SearchResult, which you can convert toString() and then do a lookup
JNDI Lists • list() finds all in the DN context • Returns NamingEnumeration, consisting of NameClass pairs • getName() method in this class
JNDI Writes • Just like we can getAttributes(), we can… • (re)bind() • Ok, so the parallel isn’t ideal • Name: DN • Object: null (Java can serialize to LDAP!) • Attributes: our good friend
JNDI Deletes • unbind(); • Must supply whole DN to it • Use search() if you don’t know what the full DN of the relevant object is • Almost never throws exception, even if the record isn’t there • idempotent
JNDI Miscellany • Name class • You don’t have to use this: it’s a bit more “civilized” way of dealing with DN’s, though • For the scope of this class, it’s acceptable just to use Strings for DN’s
Our permissions setup • Services: readable by all, writeable only by those who have password • Actors: read/write by password only • ActorStates: read/write by password only • Net effect • Client has no password, and no need of one • All servers will share the same DN and password (yes, logins are via DN too!)
What does this mean for you? • Implementation/Testing • You now know what your testing plan will look like • LDAP • You finally know all the details to use LDAP not only for your design, but also your implementation • Shouldn’t need a whole lot for the design • We give you code samples: adjust it to suit your needs