Friday, September 19, 2008

Software Quality Assurance

Overview:
Quality Assurance (QA) of code is the basis of source code analysis development. The quintessential part of distributing your code with high quality production standards is that it ensures a good product (reliable, maintainable, and manageable) and enables other organizations to easily pickup your software.

System Requirements:
  • Java: JDK 1.4 or higher
  • OS: Windows, Linux, Unix, or Mac OS X
QA Tools:
  • Ant - "Anther Neat Tool" used to assist programmers in scripting custom automated build process similar to that of "make" for C/C++.
  • CheckStyle - used to help ensure that your Java code adheres to a set of coding standards. (static analysis)
  • PMD - used to enforce certain coding rules. (static analysis)
  • FindBugs - is another static analysis tool that examines your class or JAR files looking for potential problems by matching your bytecodes against a list of bug patterns.
  • JUnit - used to incrementally assert test conditions/statements that presumably matches an expected outcome.
Installation:
The installation process is quite simple once you get the hang of it. Below is a quick walk through of installing the above QA tools on both Mac OS X/Linux platforms:

Mac OS X (Unix) / Linux Users:
** the instructions below can also be tailored for Linux users too, but just with slight differences.

Fortunately for mac users, Java and Ant come pre-installed with the latest version of Mac OS X (10.5.4). All I ended up doing was export the path variables (JAVA_HOME & ANT_HOME) to point to the installed locations on the system. *If you need to install it manually, then you can consult to instructions here.
  • $ cd
  • $ emacs .profile
  • edit file by adding the following:
  • export JAVA_HOME="/Library/Java/Home"
  • export ANT_HOME="/usr/share/ant"
  • save and close the file
  • $ source .profile
  • you can also check to see if your environment variables have been added by typing:
  • $ env
Once you get the hang of just installing one tool, the rest follow the same methodology for both Unix and Linux platforms. Below is a generalized version of installing and updating the environment variables
  • Download and extract: qa_tool (e.g. checkstyle, pmd, findbugs, etc.)
  • $ cd downloads/
  • $ wget qa_tool_url
  • $ unzip qa_tool_version.zip -d /usr/local
  • Update environment variables
  • $ cd
  • emacs .profile
  • add the following env variables
  • export QA_TOOL_HOME="/usr/local/qa_tool"
  • save and close file
  • $ source .profile
Stack + QA:
The program called stack will help us test our newly installed QA tools.
Setup project:
  1. Download project source code here: stack.zip
  2. Extract source project into development directory (workspace in Eclipse)
  3. Open Eclipse and select File>Import, General>Existing Projects into Workspace, select root directory by browsing to where the stack source was extracted, and click on Finish.
  4. Right-click on stack project, Refactor>Rename>stack-(username)
  5. Edit build.xml file by renaming the project name to match "stack-(username)"
Running Ant + QA tools:
At the command prompt/terminal, switch to the location of your stack project folder and run the following Ant commands:
  • ant clean compile
  • ant -f checkstyle.build.xml
  • ant -f dist.build.xml
  • ant -f findbugs.build.xml
  • ant -f javadoc.build.xml
  • ant -f junit.build.xml
  • ant -f pmd.build.xml
  • ant -f verify.build.xml
The last statement should render a BUILD FAILED plus something similar:
:stack-anthony.m.du directory
$ ant -f verify.build.xml

Buildfile: verify.build.xml

clean:
[delete] Deleting directory /Users/admin/Develop/java/stack-anthony.m.du/build

compile:
[mkdir] Created dir: /Users/admin/Develop/java/stack-anthony.m.du/build/classes
[javac] Compiling 5 source files to /Users/admin/Develop/java/stack-anthony.m.du/build/classes

junit.tool:
[mkdir] Created dir: /Users/admin/Develop/java/stack-anthony.m.du/build/junit
[junit] Running edu.hawaii.stack.TestClearStack
[junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.071 sec
[junit] Running edu.hawaii.stack.TestStack
[junit] Tests run: 2, Failures: 1, Errors: 0, Time elapsed: 0.031 sec

BUILD FAILED
/Users/admin/Develop/java/stack-anthony.m.du/junit.build.xml:18: Test edu.hawaii.stack.TestStack failed

Stack + QA tool fixes:
**description of errors can be found in build directory under tool directory subfolder in html format.
JUnit errors:
junit.framework.AssertionFailedError: Testing stack top of three expected same:<3> was not:<1>
at edu.hawaii.stack.TestStack.testNormalOperation(TestStack.java:37)


**edited top() logic in file: Stack.java

Checkstyle errors:
[checkstyle] /Users/admin/Develop/java/stack-anthony.m.du/src/edu/hawaii/stack/Stack.java:52: Expected an @return tag.
[checkstyle] /Users/admin/Develop/java/stack-anthony.m.du/src/edu/hawaii/stack/Stack.java:79:3: '{' should be on the previous line.


**made fixes to those minor style checks in file: Stack.java

PMD errors:
5 total:
Private field 'one' could be made final; it is only initialized in the declaration
... again for both 'two' and 'three'
**added final to all three declaration statements in file: TestClearStack.java

Avoid using implementation types like 'ArrayList'; use the interface instead
**replaced with List interface declaration in file: Stack.java

Consider simply returning the value vs storing it in local variable 'obj'
**replaced with returning top value instead of storing in file: Stack.java

FindBugs errors:
Method new edu.hawaii.stack.TestClearStack() invokes inefficient new Integer(int) constructor; use Integer.valueOf(int) instead
Method new edu.hawaii.stack.TestStack() invokes inefficient new Integer(int) constructor; use Integer.valueOf(int) instead
**replaced declaration with "Integer.valueOf(int)" in file: TestClearStack.java & TestStack.java

Final Stack + Ant Run:
amd:stack-anthony.m.du admin$ ant -f verify.build.xml
Buildfile: verify.build.xml

clean:
[delete] Deleting directory /Users/admin/Develop/java/stack-anthony.m.du/build

compile:
[mkdir] Created dir: /Users/admin/Develop/java/stack-anthony.m.du/build/classes
[javac] Compiling 5 source files to /Users/admin/Develop/java/stack-anthony.m.du/build/classes

junit.tool:
[mkdir] Created dir: /Users/admin/Develop/java/stack-anthony.m.du/build/junit
[junit] Running edu.hawaii.stack.TestClearStack
[junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.105 sec
[junit] Running edu.hawaii.stack.TestStack
[junit] Tests run: 2, Failures: 0, Errors: 0, Time elapsed: 0.015 sec

checkstyle.tool:
[mkdir] Created dir: /Users/admin/Develop/java/stack-anthony.m.du/build/checkstyle
[checkstyle] Running Checkstyle 5.0-beta01 on 5 files

pmd.tool:
[mkdir] Created dir: /Users/admin/Develop/java/stack-anthony.m.du/build/pmd
[echo] PMD found ${pmd.failure.count} problem(s).

findbugs.tool:
[mkdir] Created dir: /Users/admin/Develop/java/stack-anthony.m.du/build/findbugs
[findbugs] Executing findbugs from ant task
[findbugs] Running FindBugs...
[findbugs] Error: The path /usr/share/findbugs-1.3.5/plugin does not seem to be a directory!
[findbugs] No FindBugs plugins could be loaded
[findbugs] Output saved to /Users/admin/Develop/java/stack-anthony.m.du/build/findbugs/findbugs.xml

emma.tool:
[mkdir] Created dir: /Users/admin/Develop/java/stack-anthony.m.du/build/emma
[instr] processing instrumentation path ...
[instr] instrumentation path processed in 90 ms
[instr] [3 class(es) instrumented, 0 resource(s) copied]
[instr] metadata merged into [/Users/admin/Develop/java/stack-anthony.m.du/build/emma/metadata.emma] {in 2 ms}
[junit] Running edu.hawaii.stack.TestClearStack
[junit] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 0.261 sec
[junit] Output:
[junit] EMMA: collecting runtime coverage data ...
[junit]
[junit] Running edu.hawaii.stack.TestStack
[junit] Tests run: 2, Failures: 0, Errors: 0, Time elapsed: 0.254 sec
[junit] Output:
[junit] EMMA: collecting runtime coverage data ...
[junit]
[report] processing input files ...
[report] 2 file(s) read and merged in 7 ms
[report] writing [xml] report to [/Users/admin/Develop/java/stack-anthony.m.du/build/emma/coverage.xml] ...
[report] writing [html] report to [/Users/admin/Develop/java/stack-anthony.m.du/build/emma/coverage.html] ...
[delete] Deleting directory /Users/admin/Develop/java/stack-anthony.m.du/build/classes

emma.echo:
[xslt] Processing /Users/admin/Develop/java/stack-anthony.m.du/build/emma/coverage.xml to /Users/admin/Develop/java/stack-anthony.m.du/build/emma/coverage.brief.txt
[xslt] Loading stylesheet /Users/admin/Develop/java/stack-anthony.m.du/lib/emma/echo.emma.xsl
[concat] Emma Coverage summary
[concat] class: 100% (3/3)
[concat] method: 73% (8/11)
[concat] block: 69% (65/94)
[concat] line: 75% (15/20)

verify:

BUILD SUCCESSFUL
Total time: 7 seconds

**Here's a link to the new build: stack-anthony.m.du-6.0.921.zip

Conclusion:
I learned that functional software products must also have high quality attributes to pass being labeled a legitimate software product. Besides meeting your company's functional requirements, your software must also verify with quality assurance guidelines. In doing so, software products will be more reliable, maintainable, manageable and even distributed in a timely matter with functionality. In another exploration, I would like to find ways to quantify the quality assurance of source code. The elements of benchmarking your QA is most likely related to process aspects and operations. Perhaps, we could benchmark the number of errors or unsuccessful builds using Ant or some other tool.

No comments: